Microsoft pg_durable: PostgreSQL 的資料庫內持久化執行

Microsoft 已開源 pg_durable,這是一個旨在將持久化執行直接引入資料庫的 PostgreSQL 擴充功能。透過允許開發者使用 SQL 定義長時程、具容錯能力的工作流,pg_durable 消除了對外部編排器、獨立佇列系統或複雜狀態追蹤表來管理背景工作需求。

在 PostgreSQL 內部進行持久化執行

pg_durable 能夠建立由 SQL 驅動的函數圖 (function graphs),並由 PostgreSQL 執行與檢查點 (checkpointing)。如果資料庫崩潰、重啟或特定步驟失敗,執行將從最後一個持久化檢查點恢復,而不是需要重新啟動整個程序。

這種方法將編排邏輯(重試狀態、進度追蹤和檢查點)從應用程式層移至資料庫本身。

核心能力

  • SQL 原生定義:工作流使用如 ~>|=> 等可組合的操作符來定義。
  • 零基礎設施:系統作為 PostgreSQL 擴充功能運行,無需 Redis、Temporal 或 Airflow 等外部服務。
  • 資料庫感知原語 (Database-Aware Primitives):該擴充功能提供對排程、條件邏輯和並行執行的首選支援。
  • 容錯能力:函數狀態會持久化到 PostgreSQL,確保在崩潰和故障轉移 (failover) 期間仍能生存。

工作流範例

使用者可以啟動一個持久化函數來分步處理數據。例如,以下 SQL 會啟動一個程序,抓取未處理的文檔並進行批次更新:

SELECT df.start(
    'SELECT id FROM documents WHERE processed = false LIMIT 100' |=> 'batch'
    ~> 'UPDATE documents SET processed = true WHERE id = ANY($batch)'
);

目標工作負載與使用案例

pg_durable 針對需要將運算靠近數據以減少延遲和架構複雜度的工作負載進行了優化。

推薦使用案例

  • 向量嵌入管線 (Vector Embedding Pipelines):數據分塊、呼叫嵌入 API,並將結果 upsert 到 pgvector
  • 攝取管線 (Ingest Pipelines):對大批量的數據進行暫存、去重、轉換和發佈。
  • 排程維護:檢測資料庫膨脹 (bloat)、通知管理員,並在獲得批准後執行清理動作。
  • 扇出聚合 (Fan-out Aggregation):並行執行獨立查詢並合併結果。
  • 外部 API 工作流:直接從 SQL 處理增強、分類和 Webhook 風格的呼叫。

何時應避免使用 pg_durable

  • 簡單查詢:如果任務只是單個 INSERT ... SELECT 或標準 SQL 語句,則不需要 pg_durable。
  • 低延遲需求:它並非設計用於亞毫秒級的同步請求處理。
  • 外部密集型工作流:如果工作流跨越許多異構系統且主要存在於 PostgreSQL 之外,則使用通用編排器會更合適。
  • 複雜應用程式邏輯:無法映射到 SQL 步驟、分支、迴圈或 HTTP 呼叫的邏輯應保留在應用程式層。

技術架構

使用 pgrx 建構,pg_durable 是一個完全在伺服器內運行的 PostgreSQL 擴充功能。它由用於建立函數圖的 SQL DSL 和管理執行的背景工作程序 (background worker) 組成。

底層框架

  • duroxide:一個持久化任務框架,提供編排運行時 (runtime),包括確定性重放 (deterministic replay)、檢查點和計時器。
  • duroxide-pg:為 duroxide 提供以 PostgreSQL 為後端的狀態提供者,將運行時狀態(實例、歷史和工作佇列)持久化到專用的 duroxide.* 架構 (schema) 中。

數據組織

  • df.* Schema:儲存 DSL 圖、節點、實例和變數。

  • duroxide.* Schema:儲存由 duroxide-pg 提供者擁有的內部運行時狀態。

安裝與部署

pg_durable 目前處於 Preview 階段。標記版本提供適用於 amd64 架構下 PostgreSQL 17 和 18 的 Debian 套件。

設定流程

  1. 將套件安裝到 PostgreSQL 安裝目錄中。
  2. pg_durable 加入到 shared_preload_libraries
  3. 重啟 PostgreSQL。
  4. 建立擴充功能:CREATE EXTENSION pg_durable;

安全性與多租戶

存取權限透過顯式授權來管理。管理員必須使用 SELECT df.grant_usage('app_role'); 來授予應用程式角色權限。行級安全性 (RLS) 確保使用者只能管理自己的持久化函數實例和節點。背景工作程序角色 (預設:azuresu) 必須是超級用戶以繞過 RLS 並管理所有使用者實例。

社群觀點與權衡 (Trade-offs)

工程師之間的討論顯示,對於偏好「資料庫即編排器」方法的開發者與偏好傳統外部 DAG 排程器的人之間存在分歧。

主要反點 (Counterpoints)

  • 控制流位置:一些開發者認為控制流和佇列邏輯應該存在於版本控制的代碼 (Git) 中,而不是在資料庫內部。

  • 控制流位置:一些開發者認為控制流工作流 Workflow { "type": "object", "properties": { "body": { "type": "string", "description": "Translated article body in markdown" }, "summary": { "type": "string", "description": "Translated summary, plain text" }, "title": { "type": "string", "description": "" } } } }

Sources