具代表性的面試主題

如何解釋串流處理中的 Exactly-once 語義與外部副作用?

資料困難
OfferCC 編輯團隊發佈 更新

題幹

面試官說「這個串流任務必須 exactly-once」。請說明這句話可能指什麼,為什麼外部副作用仍可能重複,並提出處理、提交、去重與監控方案。

1. 題目

一個訂單事件流經過解析、視窗聚合與風控計算,結果寫入倉庫並觸發下游通知。任務會因 worker 崩潰、網路逾時與遲到事件重試。請解釋 exactly-once 的邊界,並設計不會因重試產生重複帳單的方案。

2. 約束與澄清

  • 先區分三層語義:訊息投遞、管線內處理結果、外部系統副作用。
  • 事件可能重複、亂序或遲到;不能假設日誌中的「處理過」就是已提交。
  • 結果需要可重播,通知等外部呼叫必須具備冪等鍵或去重能力。
  • 先明確允許的延遲、遲到視窗與丟棄策略,再討論實作。

3. 核心概念

Exactly-once processing 通常表示每筆記錄的管線結果在持久化輸出中最多反映一次,同時系統仍要保證記錄不遺失;它不等於每段使用者程式只執行一次,也不會自動涵蓋外部 HTTP、郵件或資料庫呼叫。At-least-once 輸入加上檢查點、確定性重播與結果去重,才能形成可驗證的輸出保證。

4. 參考流程

text
onEvent(event):
  key = stableEventId(event)
  state = readCheckpointOrState(key)
  result = deterministicTransform(event, state)
  writeTransactionalResult(key, result)   # unique(key)
  commitCheckpointAfterResult(key)

onExternalSideEffect(result):
  idempotencyKey = result.eventId + ":" + result.version
  callOrOutbox(idempotencyKey, result.payload)

管線內先把結果與事件 ID 寫入支援唯一約束或交易提交的儲存,再推進檢查點。外部通知透過冪等介面或 outbox 交給獨立發送器;發送器可以重複執行,但接收方只接受同一個冪等鍵一次。

5. 失敗場景與取捨

worker 在外部呼叫成功後、檢查點提交前崩潰,重播會再次呼叫外部服務;沒有冪等鍵時,不能只靠 runner 消除副作用。視窗結果還會受遲到資料與 watermark 影響,必須定義允許更正的範圍。更強的端到端保證通常增加去重狀態、交易協調與儲存成本;若業務允許重複,可選擇 at-least-once 來換取較低延遲。

6. 驗證與觀測

  • 注入崩潰、逾時、重複訊息與亂序事件,檢查同一業務鍵的最終結果。
  • 記錄輸入事件 ID、處理嘗試次數、提交版本、去重命中與外部呼叫結果。
  • 對帳「收到、處理、提交、通知」四個計數,不能只看 worker 日誌。
  • 監控重複率、遲到率、檢查點年齡、去重狀態大小與重播積壓。

7. 常見誤區

  • 把 exactly-once delivery、exactly-once processing 與 exactly-once side effect 當成同一個承諾。
  • 以為開啟框架開關後,任意自訂程式與外部 API 都自動獲得一次性效果。
  • 使用時間戳而非穩定事件 ID 去重,導致重試或批次重播產生不同鍵。
  • 忽略遲到事件、版本衝突與去重記錄的保留期限。

8. 面試評分點

能劃清保證邊界

應分別說明投遞、管線結果與外部副作用,並指出框架保證通常只涵蓋其中一部分。

能設計可重播流程

應使用穩定事件 ID、確定性轉換、交易結果提交與檢查點順序,解釋崩潰後的重播路徑。

能處理外部副作用

應提出冪等鍵、唯一約束或 outbox,並說明接收方與發送器如何共同防止重複。

能用故障注入驗證

應涵蓋重複、亂序、遲到、逾時與 worker 崩潰,使用提交資料與業務對帳驗證結論。

公開來源

同類題目

資源

產品比較

每份比較均依官方資料整理,並標示複核日期。

查看完整比較