搜尋文件

輸入關鍵字,搜尋標題與正文。

    訊息佇列與事件驅動架構文件 04/12

    發布確認與消費確認

    本文提要

    發布者收到成功、worker 收到訊息,以及匯出結果已保存,是三件不同的事。 確認訊號只對它所涵蓋的邊界提供證據,不能沿著流程自動延伸到其他系統。

    18px · 寬鬆行距

    閱讀設定

    排版預覽 · 示範文字(可捲動)

    檔案與目錄

    Linux 以一棵從根目錄 / 開始的樹狀結構組織檔案。目錄用來整理檔案,也可以包含其他目錄。

    pwd
    ls -la /home
    18px

    16、18、20、22px;隨瀏覽器文字大小縮放。

    欄寬套用於背景文章;此處預覽字級與行距。手機正文自動配合螢幕。

    文件與本文目錄
    本主題文件

    發布者收到成功、worker 收到訊息,以及匯出結果已保存,是三件不同的事。 確認訊號只對它所涵蓋的邊界提供證據,不能沿著流程自動延伸到其他系統。

    本文承接傳遞模型與獨立進度,沿用 cmd-42 與 job-42,逐一檢查交接的停止點。確認(acknowledgment,ack)的含義要連同發送者、接收者與觸發條件一起閱讀。

    查證日期:2026-11-04。RabbitMQ 使用當日標示 4.4 的文件,具體方法限定 AMQP 0-9-1;SQS 為當日文件,Kafka 固定 4.1。故障窗口為依文件行為作的概念推演,未執行 broker、SDK 或故障測試。

    先標出每個觀察點

    表格・4 欄 4 列
    訊號或紀錄誰提供證據能證明的範圍不能直接證明的事
    發布確認(publisher confirm)broker 回覆 producer依產品與設定接受發布consumer 已處理、外部資料庫已提交
    Consumer 收到訊息consumer 的接收結果有一次投遞到達檔案已完成、之後不會重投
    Consumer ack/SQS deleteconsumer 對 broker 的進度操作依協定結束該投遞或刪除訊息broker 已查驗業務效果
    工作成功與結果紀錄業務服務/儲存邊界達到應用契約的完成條件通知與其他下游也全部成功

    RabbitMQ 明確區分 publisher confirms 與 consumer acknowledgments,兩者互不知情。producer 可以在 consumer 尚未啟動時取得 confirm;consumer ack 也不會反向告訴 producer 哪筆業務已完成。參考 RabbitMQ:Consumer Acknowledgements and Publisher Confirms。

    發布確認:要問是否路由,也要問保存到哪裡

    在 RabbitMQ AMQP 0-9-1 中,可路由訊息的 confirm 與目標 queues 接受有關;無法路由到 queue 的訊息也可能收到 confirm。若使用 mandatory,未路由訊息會先 basic.return 再 confirm,因此 producer 必須處理 return,不能把單一 confirm 當成「工作 queue 一定已收到」。參考 RabbitMQ:When Will Published Messages Be Confirmed by the Broker?。

    保存條件也要明示。Durable queue 描述 queue 的重啟保存屬性;persistent message 是訊息的保存模式,兩者不是同一個開關。對 persistent 訊息送入 durable queue,文件將確認條件連到落盤;quorum queue 則涉及 quorum replicas 接受。這不表示任意數量的永久節點損毀都能恢復,也不表示副作用與訊息一起提交。參考 RabbitMQ:Queues,Durability、Quorum Queues,Data Safety。

    本例若 producer 發出 cmd-42 後斷線,沒有取得 confirm,結果就是未知:訊息可能沒被接受,也可能已被接受但確認遺失。若重送,consumer 就可能再次看到同一命令。確認協定縮小未知範圍,不能消除所有重複。

    消費確認:太早可能漏做,太晚可能重做

    RabbitMQ manual ack 由應用在處理後送出;未確認投遞在 channel/connection 關閉時可重新排入 queue。auto ack 則在傳送時視為成功,consumer 停止可能留下未處理的工作。參考 RabbitMQ:Consumer Acknowledgement Modes、Automatic Requeueing。

    下面假設成功效果是「保存可用檔案,並提交 job-42 成功狀態」,且 broker 與業務儲存不共享交易:

    表格・3 欄 3 列
    歷程停止時發生的事恢復後風險
    先 ack,再保存結果broker 已允許移除投遞,worker 在效果前停止這條訊息路徑無法保證再處理,可能漏做
    先保存結果,再 ack成功效果已保存,worker 在 ack 前停止訊息可再投遞,可能重做
    保存結果、送出 ack,但連線中斷worker 不確定 broker 是否收到 ack仍須承受可能的再投遞

    所以「處理後才 ack」通常有助避免提早丟掉工作,但它仍要求重複處理安全。應用需核對 job-42 的既有結果,並把去重與適用的業務變更放在可靠邊界內。若檔案、資料庫與外部通知分屬不同系統,不能只加一張去重表就宣稱所有效果恰好一次。原子邊界的基礎見從重送請求到冪等副作用。

    SQS:收到後暫時不可見,不是已刪除

    SQS 的 ReceiveMessage 不移除訊息;visibility timeout(可見性逾時)期間訊息暫時不可見,處理完成還要呼叫 DeleteMessage。未及時刪除,訊息會再次可見;standard queue 即使在 timeout 內也不能保證沒有重複投遞。參考 SQS:Visibility timeout。

    用自訂數值推演:worker A 需要 45 秒,可見性期限是 30 秒;第 30 秒訊息再次可見,worker B 可能取得它,A 卻仍在執行。這不表示 broker 已證明 A 失敗,也沒有遠端終止 A 的程序。

    可以按處理時間規劃期限並在需要時延長,但延長不是外部資源寫入鎖。若兩個 worker 同時修改結果,應由業務儲存與處理契約拒絕不合法的重複或過期更新。這是由投遞與程序執行分離推得的限制,不是 visibility timeout 自帶的保護。

    Kafka:提交位置也需要對照效果

    在本文使用的 Kafka traditional consumer group 模型中,consumer 提交位置供恢復使用;它不是刪除某筆紀錄,也不證明外部資料庫已寫入。先提交位置再做效果,停止可能造成漏處理;先做效果再提交位置,停止可能造成重做。參考 Kafka 4.1:Design,Consumer position、Message Delivery Semantics。

    Kafka 內部的交易處理有自己的適用範圍與設定;寫到外部目的系統仍需配合。不能把某個平台的 exactly-once 名稱延伸成「檔案、通知與所有資料庫各發生一次」。本篇只建立提交位置與業務效果分離的觀察方式。

    用停止點核對設計

    對 cmd-42 問四件事:producer 取得什麼發布證據?未路由如何得知?worker 何時可以結束投遞?效果已發生卻未確認時,重投會做什麼?若答案只是「有 ack」,還沒有說明足夠的邊界。

    下一篇接續消費並行、分區與順序,之後以重試、死信與 Outbox 處理恢復及雙寫。它們各自解決不同問題;不能只憑確認訊號宣稱完整流程可靠。

    相關文件