題幹與適用場景
一個 HTTP 請求發布訊息後由非同步消費者處理,你如何傳播 Trace Context 並確保重試、批次與跨租戶安全?這道題適用於後端、可觀測性與訊息系統面試。重點是在跨執行邊界保持因果關聯,同時避免把請求上下文當成永久授權或業務資料。
面試官考察點
- 是否理解
traceparent、可選的tracestate與傳播器的職責邊界。 - 是否能區分生產者、訊息處理與每次重試的 span 和 parent 關係。
- 是否處理批次訊息、延遲消費、死信、取樣與上下文過期。
- 是否避免傳播敏感 baggage、跨租戶資料或可偽造的信任資訊。
回答前需要釐清的問題
先確認傳輸協定、訊息是否持久化、是否支援批次與重試,以及消費者是否可能跨服務或跨信任域。明確要關聯的是一次業務操作、一個訊息,還是一批訊息。再問取樣策略、追蹤系統保留期、租戶隔離,以及是否允許外部生產者注入上下文。最後確認失敗訊息如何進入死信,以及人工重播是否建立新的追蹤分支。
30 秒回答框架
「入口服務提取並驗證傳播標頭,發布訊息時注入最小的 trace context。消費者從訊息載荷提取它,建立獨立的消費 span,並把每次重試、批次與死信表示為清楚的子關係。跨信任域只接受受控欄位,敏感 baggage 不出域;取樣與過期策略由平台統一定義,重播使用新的 trace 標識並保留原始關聯。」
分步驟深入解答
- 定義邊界:把 HTTP 入站、訊息發布、訊息傳輸與消費處理建模為不同執行單元,約定誰負責注入與提取。
- 傳播載體:優先使用標準傳播格式放在訊息 headers 或受控 metadata;不要把完整請求、身分令牌與任意 baggage 複製進訊息。
- span 關係:發布者建立 producer span,消費者建立 consumer span;批次時記錄訊息關聯,避免把整批誤標成單一請求。
- 重試與死信:每次嘗試有獨立 span 與 attempt 屬性,保留原始訊息關聯;死信與人工重播建立新分支,避免偽造歷史時間線。
- 安全與治理:限制跨域注入、清洗使用者可控欄位、隔離租戶標籤,設定取樣、保留與上下文大小上限。
高品質示範回答
我會把傳播分成標準上下文、業務關聯與安全邊界三層。HTTP 入口只提取符合格式的傳播標頭,驗證版本與長度後建立伺服器 span。發布訊息時,生產者 span 將最小 trace context 注入訊息 metadata,同時另存不可變的業務事件 ID,兩者用途不同。消費者提取 metadata,建立 consumer span;如果一條訊息觸發多個下游操作,每個操作建立自己的子 span。批次處理不把所有訊息強行合併成一個 parent,而是記錄批次 span 與有限的訊息連結。每次重試增加 attempt 與退避資訊,仍保留原始事件 ID;進入死信後,人工重播建立新的 trace,連回原始 trace,避免把新執行偽裝成舊執行。跨租戶或外部生產者的 baggage 預設丟棄,只允許平台核准的低敏欄位。最後用上下文大小、提取失敗率、訊息到消費的關聯率、重試可見性與跨租戶洩漏測試驗證方案。
常見錯誤
- 把 trace ID 當成認證憑證或業務冪等鍵。
- 將完整 HTTP headers、使用者輸入或 token 原樣寫入持久化訊息。
- 把批次消費與多次重試都掛在同一個 span 上,導致時序失真。
- 死信重播複用舊 trace,無法區分原始失敗與新嘗試。
- 只講 SDK 呼叫,不說明跨信任域、取樣、保留與上下文大小治理。
追問及應對
訊息被重試十次,應該有幾個 span?
至少為每次實際處理嘗試建立可區分的 span,並透過 attempt、事件 ID 與連結關聯原始生產操作。這樣既能比較每次延遲,也不會把十次執行誤報為一次。
批次訊息如何建立 parent?
建立代表批次的消費 span,再為需要分析的訊息建立連結或子 span。不要任意選第一條訊息作為整批 parent;取樣不足時保留批次級統計和關聯 ID。
外部客戶可以注入 tracestate 嗎?
可以接收符合協定的欄位,但不能預設信任其內容。跨信任域要限制長度、鍵集合與轉發範圍,清除敏感或高基數欄位,並避免把它用於授權決策。
人工重播死信時如何保持可追蹤?
為重播建立新的 trace 與執行 span,記錄原始訊息 ID、操作者、原因與重播批次。新舊鏈路透過受控連結關聯,保留原始失敗的不可變記錄。