搜尋文件

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

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

    重播、投影與歷史資料

    本文提要

    搜尋規則修正後,可以重新計算搜尋結果;通知程式修正後,卻不能因此把過去的完成通知全部再寄一次。兩者都會重新讀事件,但期望的效果不同。

    18px · 寬鬆行距

    閱讀設定

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

    檔案與目錄

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

    pwd
    ls -la /home
    18px

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

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

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

    搜尋規則修正後,可以重新計算搜尋結果;通知程式修正後,卻不能因此把過去的完成通知全部再寄一次。兩者都會重新讀事件,但期望的效果不同。

    本文接續訂閱拓樸、路由與隔離。重播(replay)是重新讀取既有事件;投影(projection)是依來源資料計算出適合某種查詢的資料表示。重播是否安全,取決於保存內容、讀取程式與效果邊界,不能只看 broker 是否提供倒回位置的功能。

    查證日期:2026-11-04。Kafka 固定 4.1,Azure 與 Google Cloud 為當日線上文件。evt-90、投影世代與切換步驟皆為自創概念設計,未部署、執行重播或驗證故障。

    同一事實再讀一次,不是再發起一次意圖

    export-intent-7 要求產生匯出,建立 job-42;完成事件 evt-90 陳述檔案已按契約保存。搜尋重建時再讀 evt-90,是在重新理解這個既有事實,事件身分仍保持相同。它不應偷偷建立新的 cmd-42 或再次產生匯出。

    若使用者明確要求「重新匯出目前內容」,那是新業務意圖,應有新的意圖與工作識別。若營運者要求「補寄未送達的通知」,則是受控補救操作,需記錄對象、原因與效果鍵;不能靠把事件改成新 ID 來繞過去重。

    同樣地,「重播已完成」應說明完成什麼。讀過所有 offset、重建資料寫入成功、搜尋已切到新資料、外部通知確定送達,是不同觀察點。歷史讀取進度不能代替業務效果證據。

    位置只有在資料還存在時才有用

    Kafka 的 offset 是分區內讀取位置。Consumer 可以倒回,但已被保存政策移除的紀錄不會因為持有舊 offset 而復原;各分區還需各自追蹤進度。參考 Kafka 4.1:Design,The Consumer。

    本例先假設搜尋需要重建最近一年的結果。如果 broker 只保存七天事件,必須另有足夠且受治理的歷史來源,例如權威資料快照加上其後的變更。七天是自訂情境,不是 Kafka 預設。不能拿今天的資料庫快照與任意一天的 offset 拼接:快照涵蓋到哪個一致性邊界、之後的更新從哪裡接續,必須可以證明沒有缺口。

    Log compaction(日誌壓實)按 key 清理被後續值取代的舊紀錄,適合某些重建最新狀態的用途,不保留每次變化的完整歷史。Kafka 4.1 的 tombstone 是帶 key、值為 null 的刪除標記;它本身也會在保留期限後清除。落後過久的 consumer 可能錯過刪除;不能把 compacted topic 當成永久稽核帳本。參考 Kafka 4.1:Log Compaction。

    Kafka 4.1 可以同時採用 compact 與 delete;即使按 key 壓實,舊 segment 仍受時間或大小刪除政策限制。因此「保留每 key 最新狀態」也不能脫離實際設定,理解成每個 key 永遠都在。參考 Kafka 4.1:Topic Configs,cleanup.policy。

    因此需先定義 key 代表工作、結果還是事件。若以 job_id 壓實,最後狀態可能足夠重建「目前可搜尋的匯出」,卻不足以統計該工作每次狀態轉移。若以事件 ID 當 key,也不能因此宣稱無限保存,仍要核對清理政策與容量。

    Google Pub/Sub 的 snapshot 保存訂閱的確認狀態,不是永久應用備份;重播已確認訊息也需要符合 retention 或有效 snapshot 等前提。按 timestamp seek 採用 broker 發布時間,不能直接當成「回到業務發生時間」;既有 filter 也會限制重送範圍。這些是該產品的能力邊界,不是所有 queue 都能倒帶的保證。參考 Pub/Sub:Replay and purge messages with seek。

    重建也要讀懂舊格式與刪除

    重播程式會接觸仍在保存範圍內的所有版本,而非只有目前 producer 的格式。需要保留 writer schema 或足夠識別資訊、舊版語意說明及對應 reader。轉換器可以把舊欄位轉成內部統一表示,但不能發明當年未記錄的值。未知語系可保留未知,不能為了讓投影欄位非空就補造使用者偏好。

    刪除資料也需納入歷程。假設 artifact-18 曾完成,之後因使用者刪除或到期而不可再讀;若重建只看 ExportCompleted,就可能把已移除結果重新放回搜尋。需要可取得的刪除事件、權威現況核對或可證明已排除刪除項目的快照;其範圍與時點要和重建一致。

    若歷史只存 result_id,現在查不到內容,不等於歷史處理失敗;它可能是合法刪除。反過來,若事件保存全文,現在刪除資料庫也不代表事件、DLQ、備份與重建資料已清除。歷史保存要同時滿足重建與資料治理,不能先宣稱永久保留,之後才處理敏感資料散落的結果。

    用新世代重建,明確接住即時更新

    投影世代(generation)區分不同建置版本;checkpoint(檢查點)記錄某個世代已安全套用到哪些來源位置。本例搜尋使用可交易的資料儲存來保存投影與去重紀錄,不假設外部搜尋引擎能和 inbox 共用原子交易。切換邊界 B 是每個分區的「下一個待讀位置」;完成至 B 表示已套用 B 之前所有可讀事件,接續從 B 起讀,並非要求 offset 整數沒有間隙。

    表格・3 欄 5 列
    階段本例動作可觀察的安全條件
    建立 g2保持查詢使用 g1,建立空的 g2讀取者不會查到半套資料
    載入歷史從已驗證起點,依分區順序重建 g2投影更新、去重與檢查點在同一交易提交
    追上即時流g2 繼續處理載入期間新增的事件新事件沒有在歷史結束和即時開始間消失
    切換前交接停止 g1 writer 並收束在途交易,選定不落後其已提交進度的各分區邊界 B;g2 只追趕至 B 後停止g1 不再接受提交,g2 已完整套用 B 之前事件,兩者沒有在途寫入
    切換與恢復原子切換查詢指向 g2,讓唯一有效 writer 從 B 接續切換後事件只由持有有效世代權限的 writer 提交

    這個概念方案容許來源仍接受新工作,切換期間的新事件先保留在可追讀來源;暫停的是舊投影套用,g2 在受控追趕後也暫停以完成切換,不是宣稱全系統停止。若緩衝容量、保留期或寫入權限控制不足,就不能採用這項切換承諾。單純「g2 看起來追上了」之後改別名,可能讓剛寫進 g1 的新結果在 g2 消失。

    檢查點必須在該位置之前的效果都已提交後前進;並行處理不能跳過未完成事件。若程序在本地交易後、broker 確認前中斷,重送可由同一交易邊界內的去重紀錄辨認。這沿用Outbox 與消費去重的責任範圍,沒有把本地交易擴張到外部系統。

    去重範圍也要隨目的改變。g1 處理過 source + evt-90,不應阻止 g2 建立它的新表示;因此搜尋可用「consumer 用途 + generation + source + id」作為本例去重鍵。通知則不應因部署或搜尋世代改變,就把已寄送事實視為全新通知。

    外部副作用要有獨立閘門

    外部副作用是資料重算以外、會影響其他系統或人的操作,例如寄信。預設的搜尋重建身分只允許寫入新投影,不能呼叫通知 provider;僅靠事件中的 replay: true 提醒程式自律,不能取代執行路徑與權限限制。

    通知 consumer 正常重試或受控補寄時,仍需使用穩定效果鍵並查明 provider 的冪等契約、有效範圍與期限。若 provider 已接受寄送卻遺失回應,本地標記「待送」不能證明未寄;沒有可用的冪等或查詢契約時,應保存未知狀態、對帳並按政策補救,不能承諾自動重試絕不重寄。

    因此通知去重通常依通知用途及原事件身分,而不是每次重播產生新的批次 ID。批次 ID 可以追蹤操作,但不應使同一外部效果避開原有防重。若確實要再次通知,那是需要明確授權與新效果身分的業務操作。

    事件驅動不必等於 Event Sourcing

    事件溯源(event sourcing)把事件序列作為權威紀錄,再由它重建業務狀態;一般事件驅動架構則描述 producer、傳遞通道與 consumer 的互動。本例仍以工作資料庫為匯出狀態的權威來源,透過 Outbox 發布完成事實,即使可重播搜尋,也不因此成為事件溯源。參考 Azure:Event-driven architecture與 Azure:Event Sourcing pattern。

    若系統沒有保存足夠事件來重建全部業務狀態,就不該以「有 event log」宣稱具備完整事件溯源能力。是否採用該模式涉及權威資料、併行控制與歷史演進,應由需求決定;搜尋重建本身不要求改寫整個儲存模型。

    下一篇轉向積壓、觀測與故障驗證,檢查讀取位置、事件年齡與業務終態,如何共同證明恢復確實前進。

    相關文件