題幹與適用場景
這道題適合後端、平台和分散式系統面試。面試官要聽到邊界:SQS 會在去重時間窗內把相同去重 ID 視為重複訊息,並持續追蹤該 ID,即使訊息已被接收和刪除;這不等於外部資料庫、付款或郵件副作用天然 exactly-once。
面試官考察點
高品質回答會區分生產端去重、FIFO 順序、消費者可見性逾時、刪除確認和業務冪等。AWS 文件把去重 ID 定義為防止重複投遞的令牌;未明確提供時,啟用 content-based deduplication 可用訊息本文雜湊產生。回答還應說明視窗、失敗重試和監控,而不是只說「FIFO 就不會重複」。
回答前需要釐清的問題
語意邊界
先問面試官要的是佇列層重複抑制、至少一次處理,還是業務結果一次生效。把「訊息只出現一次」和「訂單只扣款一次」分開。
去重輸入
確認生產者是否明確產生穩定的 MessageDeduplicationId、是否啟用以內容為基礎的去重、訊息群組如何劃分,以及重試間隔是否落在五分鐘視窗內。
失敗點
畫出接收、處理、寫入副作用、DeleteMessage 的時間線;確認消費者崩潰、可見性逾時、網路重試和下游逾時分別會發生什麼。
30 秒回答框架
「FIFO 的去重 ID 在五分鐘視窗內抑制相同訊息再次進入佇列,並保留該 ID 的追蹤;它解決的是佇列層的重複傳送和順序約束,不自動讓外部副作用 exactly-once。消費者應以穩定業務鍵建立冪等紀錄,在副作用與狀態寫入之間採用同一交易邊界或可重試的 outbox,再在成功後刪除訊息。崩潰時允許重投,但重複執行只會讀取已完成紀錄。」
分步驟深入解答
第一步:定義可驗證的保證
說明相同 deduplication ID 在五分鐘 deduplication interval 內會被視為重複;即使訊息已接收並刪除,SQS 仍繼續追蹤該 ID。不要把這個視窗描述成永久去重。
第二步:區分生產與消費
生產端用穩定 ID 表示同一業務命令;內容雜湊只在訊息本文足以代表命令時適用。消費端必須按訂單號、付款意圖或命令 ID 建立唯一限制,因為視窗過後重試仍可能是同一業務動作。
第三步:覆蓋崩潰視窗
若消費者先寫資料庫再崩潰,訊息可能在可見性逾時後再次出現。讓副作用寫入和冪等鍵狀態處於同一交易,或用 outbox 讓後續傳送可重播;只有確認處理完成後才刪除訊息。
第四步:處理順序與毒訊息
需要順序時使用相同 MessageGroupId,並設定合理的可見性逾時。對持續失敗的訊息轉入 dead-letter queue,同時記錄原始 ID、接收次數和失敗原因,避免無限重試阻塞訊息群組。
第五步:驗證與監控
測試生產重試、消費者在寫入後崩潰、DeleteMessage 逾時和視窗外重播。監控重複業務鍵、ApproximateReceiveCount、DLQ 深度、可見性逾時和端到端延遲;告警應能區分佇列重複與業務重複。
高品質示範回答
我會把 SQS 的五分鐘去重當作傳輸層保護,不把它當作付款結果的一次性保證。生產者為每個付款意圖產生穩定命令 ID,重試時重用該 ID;消費者先在資料庫的 inbox 表上用命令 ID 建立唯一限制,再在同一交易中寫入訂單狀態和 outbox 事件。交易提交後刪除訊息。若寫庫後程序崩潰,訊息重投只會命中已處理紀錄,不會再次扣款。監控會統計重複命令、接收次數和 DLQ,另外做視窗內、視窗外及 DeleteMessage 失敗的故障測試。
常見錯誤
- 錯誤表現: 說 FIFO 等於永久 exactly-once。→ 失敗原因: 忽略五分鐘視窗和消費端崩潰。→ 修正方法: 明確去重 ID 的時間範圍,並設計業務冪等。
- 錯誤表現: 每次重試都產生新的 deduplication ID。→ 失敗原因: 同一業務命令會被當成不同訊息。→ 修正方法: 重試重用穩定命令 ID。
- 錯誤表現: 處理完成前刪除訊息。→ 失敗原因: 下游失敗時訊息遺失。→ 修正方法: 成功提交後再 DeleteMessage,並允許可見性逾時重投。
- 錯誤表現: 只依賴訊息本文雜湊。→ 失敗原因: 時間戳或無關欄位變化會繞過去重。→ 修正方法: 對業務命令明確定義穩定 ID。
追問及應對
追問一:五分鐘後收到相同命令怎麼辦?
用持久化的業務冪等紀錄判斷是否已完成;佇列去重只能降低短視窗重複,不能取代長期業務狀態。
追問二:為什麼不先刪除再處理?
先刪除會把下游失敗變成訊息遺失。除非業務允許丟棄並有其他可靠來源,否則應先完成可重試處理,再刪除。
追問三:outbox 解決了什麼?
它把業務狀態提交和待傳送事件放進同一資料庫交易,發布器可安全重試;它仍要求下游按事件 ID 冪等。
追問四:如何證明沒有重複扣款?
用故障注入涵蓋寫入後崩潰、刪除逾時和視窗外重播,核對資料庫唯一限制、支付提供商冪等鍵及稽核日誌,而不是只看佇列指標。