Just Use Postgres: The Case for Database-Backed Durable Workflows
持久性工作流(Durable workflows)是構建可靠程式的強大工具。其核心概念很簡單:隨著程式運行,它會定期將進度檢查點(checkpoint)存儲到資料庫中。如果程式崩潰或失敗,它可以從最後一個檢查點重新載入並從最後一個完成的步驟繼續執行。這本質上是軟體工程中的「存檔」機制。
傳統上,這是透過**外部編排(external orchestration)**來實現的。像 Temporal、Airflow 和 AWS Step Functions 這樣的系統使用中央編排器來協調步驟、將任務派發給工作人員(workers),並在獨立的資料儲存中記錄結果。雖然有效,但這種架構引入了顯著的維運開銷和新的故障點。
反對外部編排的論點
外部編排通常在根本上過於複雜。如果持久性工作流的主要目標是在資料庫中記錄狀態檢查點,那麼沒有邏輯理由去維護一個獨立的編排器伺服器。相反地,資料庫本身就可以充當編排器。
在一個以 Postgres 為後盾的持久性工作流系統中,應用程式伺服器直接與 Postgres 通訊。其流程如下:
- 提交:客戶端在 Postgres 的 workflows 表中建立一個分錄。
- 執行:應用程式伺服器輪詢該表以進行任務出隊(dequeue)並執行工作流。
- 檢查點記錄:當伺服器執行工作流時,它會直接將每個步驟的輸出檢查點記錄到 Postgres。
- 恢復:如果伺服器崩潰,另一台伺服器會從最後一個檢查點恢復工作流。
透過使用鎖定子句(例如 SKIP LOCKED)和資料庫完整性約束,伺服器可以協作進行任務出隊,並在沒有中央協調器的情況下檢測重複工作。
Postgres 原生方法的優點
1. 可擴展性與可用性
使用 Postgres 意味著可擴展性和可用性不再是「編排器問題」——而是「資料庫問題」——而 Postgres 是一個研究非常透徹的領域。
- 水平擴展:可以透過增加更多工作伺服器來增加容量。
- 垂直擴展:單個 Postgres 伺服器可以每秒處理數萬個工作流。
- 分散式選項:對於極端規模,可以使用像 CockroachDB 這樣的分散式 Postgres 變體或分片(sharded)設置。
- 可用性:高可用性是透過串流複製(streaming replication)和多可用區(multi-AZ)部署來實現的,利用了數十年現有的資料庫工程技術。
2. 內建的可觀測性
因為工作流狀態和檢查點都存儲在關聯式資料表中,可觀測性基本上是「免費」的。任何關於工作流狀態的分析查詢都可以用 SQL 表達。例如,尋找上個月所有出錯的工作流變得非常簡單,只需一個帶有 WHERE 子句的 SELECT 語句,而不是需要專門的工具或掃描許多編排器使用的專有鍵值儲存(key-value stores)。
3. 減少安全攻擊面
外部編排器會產生兩個潛在的單點故障:編排器本身及其資料儲存。它們還需要存取敏感的應用程式數據來處理檢查點。透過將編排排轉移到 Postgres,唯一的故障點就是資料庫——這已經是大多數應用程式的關鍵基礎設施。這消除了對額外敏感基礎設施進行加固和審計的必要性。
關鍵視角與權衡
雖然以資料庫為後盾的 approach 很有吸引力,開發者社群對其提出了幾個重要的考慮因素和潛在陷阱。
「自建 vs. 購買」的複雜度
其中一個最重要的反對論點是,雖然資料庫是一個很好的起點,但功能齊全的工作流引擎需要的不僅僅是狀態儲存。正如社群成員所指出的,一旦你需要進階功能, 「just use a database」的故事就會迅速轉變為:正在構建一個功能很差的工作流引擎副本,加上一堆工作人員。
Once you need retries, backoff, timeouts, cancellation, versioning, visibility, task routing, rate limits, leases, heartbeats, detection of stuck-workers, replay/debugging semantics, workflow migration, fanout/fanin, long timers, audit trails, and operator tooling, the “just use a database” story becomes “build a poor copy of a workflow engine plus a bunch of workers.”
正確性與一致性
一些批評者認為,對於以資料베이스-backed workflows 的 簡單實現,在正確性方面可能有些「含糊其辭」。在崩潰時確保強一致性保證是困難的,且天真的偽代碼實現可能會在生產環境中導致數據正確性問題。
規模化效能
雖然 Postgres 是多功能的,但有人認為在極端規模(數 TB 的數據)下,在雲端運行持久性 Postgres 的成本可能會變得非常高昂。對於某些開發者,他們選擇了基於磁碟日誌(disk-log)的架構來降低成本,而其他人則建議對於較小的負載,甚至 SQLite 也是持久性工作流的一個可行替代方案。
冪等性(Idempotency)的力量
除了複雜的檢查點記錄,另一種選擇是使用冪等操作。如果工作流中的每個步驟都是冪等的,系統可以簡單地在失敗時從頭重新啟動任務,將已完成的步驟視為 no-ops,直到到達失敗點。當工作流狀態過大而無法有效進行備份時,這可以是一個更穩健的策略。
總結:選擇你的路徑
對於許多應用程式,使用 Postgres 作為持久性工作流引擎的簡單性是一個壓倒性的優勢。它集中了數據,減少了基礎設施複雜度,並利用 SQL 的力量來實現可觀測性。然而,對於需要複雜編排模式(例如複雜的 fan-out/fan-in 或複雜的版本控制)的組織,專用的編排器可能仍然是正確的選擇,以避免「NIH」(Not Invented Here)症候群和長期維護的負擔。