題干與適用場景
一個 worker 每次從佇列取出 100 個事件,聚合後只呼叫一次下游 API。每個事件可能來自不同 Trace,worker 也可能由排程或人工重放觸發。請設計追蹤模型,既能回溯每個來源,又不把 100 條不相關請求偽裝成單一父子樹。
OpenTelemetry 將 Span 描述為可形成樹的操作,並允許一個 Span 關聯零個或多個 Link。官方概覽明確把「批次由多個入站 Span 發起」列為 Links 的典型場景。
面試官考察點
考察候選人是否理解 parent 表示單一目前上下文,Link 表示因果相關但非父子關係;能否控制連結數量、採樣和高基數屬性,避免 Trace 爆炸,同時讓指標和日誌仍可關聯。
回答前需要釐清的問題
- 批次是否包含不同租戶、不同安全等級或不同業務類型?
- 下游呼叫是一次合併請求,還是仍可拆成每個事件的操作?
- 需要按單一事件追責、延遲分析,還是只看批次吞吐?
- 採樣由入口決定,還是 worker 可以保留部分來源上下文?
- Link 屬性是否允許放事件 ID、租戶 ID 或敏感欄位?
30 秒回答框架
「批次處理 Span 以 worker 或批次觸發上下文為 parent;100 個入站 Span 作為 Links,因為它們共同促成一次批次卻不構成單一父子鏈。每個 Link 只保留必要的 SpanContext 和低基數屬性,設定連結上限並統計截斷數。批次 Span 記錄大小、等待、處理、下游耗時和失敗數,日誌用批次 ID 與事件雜湊關聯。敏感租戶欄位需脫敏,採樣要保證失敗批次和重放批次可定位。」
分步深入解答
第一步:區分 parent 與 Link
Parent 表示目前操作從哪個單一 Span 繼續,形成 Trace 樹並繼承 TraceId。Link 只表示一個相關 SpanContext,可來自同一或不同 Trace。批次有多個同等來源時,不能任選一個事件作父節點,再把其他事件掛成子節點。
批次處理 Span
parent: worker / scheduler context
links: event-1 SpanContext ... event-100 SpanContext第二步:保留跨邊界的 SpanContext
從訊息標頭提取 TraceContext,驗證格式和採樣標記後建立 Link;不要把完整訊息、使用者輸入或原始權杖寫入 Link 屬性。若訊息沒有合法上下文,記錄「無來源上下文」計數,不要產生偽造 TraceId。
第三步:控制連結規模與成本
100 個連結只是題設上限,生產批次可能更大。設定 SDK 的 link count limit 或應用層上限,優先保留錯誤、重試和關鍵租戶的代表性來源,並記錄 dropped-link 數量。連結被截斷時要在批次指標與日誌中可見。
第四步:設計批次 Span 生命週期
Span 覆蓋等待批次、反序列化、聚合、下游呼叫和提交結果;按階段記錄事件或指標。任何建立的 Span 都必須結束,即使處理失敗、取消或部分提交。不要讓單一事件的長處理掩蓋整個批次 Span 的結束時間。
第五步:處理採樣與失敗可見性
入口採樣決定是否保留來源 Trace,但 worker 應為失敗、重試、死信和人工重放設定保底策略。Link 在 Span 建立時可能影響採樣,建立後加入的 Link 不一定能被採樣器使用,因此需要明確採樣順序和降級行為。
第六步:把追蹤、指標和日誌分工
Trace 解釋單一批次的因果關係;指標承載批次大小、佇列等待、處理延遲、成功/失敗和截斷計數;日誌用批次 ID、事件雜湊和重放 ID 定位樣本。不要把事件 ID 作為無限基數的指標標籤。
第七步:隔離租戶與隱私
跨租戶批次需要在 Link 和日誌中使用不可逆雜湊或內部引用,並在匯出前做屬性過濾。若不同安全等級不能共存,應按租戶或權限拆批,避免一個 Trace 讓低權限操作者看到其他租戶上下文。
第八步:驗證查詢與故障場景
測試單一來源、混合 Trace、缺失上下文、連結超限、採樣遺失、下游重試、部分失敗、死信和重放。驗證從批次 Span 能跳回保留的來源 Trace,也能從指標定位被截斷或未採樣的批次。
高品質示範回答
「批次 Span 以 worker 或排程器為 parent,訊息中的每個來源 SpanContext 作為 Link。這樣保留 100 個事件共同促成一次下游呼叫的事實,避免偽造父子樹。我會限制連結數量並記錄丟棄計數,過濾租戶和敏感屬性;用指標記錄批次大小、佇列等待、下游延遲、失敗與重試,日誌用批次和重放 ID 關聯。採樣策略為失敗批次保底,測試缺失上下文、混合 Trace、超限和重放。」
常見錯誤
- 任選第一條訊息作 parent → 偽造因果樹 → 批次用共同 parent,其餘來源用 Links。
- 把整個訊息放進 Link 屬性 → 洩漏敏感資料並增加成本 → 只保留必要、脫敏的低基數欄位。
- 無限制加入 Links → Span 體積和匯出成本失控 → 設定上限並記錄截斷。
- Span 只在成功路徑結束 → 錯誤和取消留下懸掛 Span → 用 finally 或作用域自動結束。
- 用事件 ID 作指標標籤 → 高基數爆炸 → 把細節留給日誌或 Trace。
- 認為建立後 Link 一定影響採樣 → 重要來源被採樣遺失 → 建立 Span 前準備採樣所需上下文。
追問及應對
追問一:批次只有一個訊息時還需要 Link 嗎?
可以直接以該訊息上下文作 parent;若 worker 有獨立生命週期,也可用 worker parent 加一個 Link,取決於是否要把批次視為該請求的直接子操作。
追問二:Link 會把不同 Trace 合併成一個 Trace 嗎?
不會。Link 表示相關性,保留各自 TraceId;查詢系統需要提供從 Link 跳轉來源 Trace 的能力。
追問三:如何選擇被截斷的來源?
按錯誤、重試、重放、關鍵租戶或確定性採樣保留,並記錄總數和 dropped 數;不要靜默保留前 N 條造成偏差。
追問四:批次失敗如何保證可診斷?
讓失敗批次和死信重放帶獨立批次/重放 ID,保留錯誤事件連結或摘要;指標記錄失敗類型,日誌提供受控的事件引用。
追問五:Link 屬性能否放 tenant.id?
只有通過權限、基數和隱私評估才可放內部穩定標識;跨租戶匯出通常應雜湊或刪除,並避免當作高頻指標標籤。