微软开源 pg_durable:实现数据库内持久化执行
速览
微软近日开源了 pg_durable 项目,旨在为数据库应用提供持久化执行能力。该技术允许开发者在数据库内部可靠地运行长时间任务,无需依赖外部编排系统。此举有助于简化分布式事务处理,提升应用的容错性和开发效率。
AI 深度解读
pg_durable:微软将持久化执行引入 PostgreSQL
背景
在数据工程和 AI 管道开发中,团队通常需要在 PostgreSQL 中管理状态,同时依赖外部组件(如 cron 任务、工作进程、消息队列和状态表)来确保后台任务的可靠性。这种“拼凑”式的架构不仅增加了运维复杂度,还引入了脆弱性。例如,长事务会持有锁并导致 WAL(Write-Ahead Log)增长,使得批量作业在大规模下变得不稳定;而并行工作在应用层处理则容易引发部分失败和状态漂移。此外,一旦数据库崩溃或重启,之前已成功的部分工作往往需要重新运行,导致人工清理和不确定性的重放。
为了解决这一痛点,微软开源了 pg_durable。该项目旨在将“持久化执行”(Durable Execution)这一行业标准模式直接带入 PostgreSQL 内部,无需额外的服务基础设施。其核心理念是“将计算靠近数据”,让工作流逻辑以 SQL 原生方式定义,并由数据库本身负责状态的检查点保存与恢复。
核心内容
pg_durable 是一个 PostgreSQL 扩展,它允许用户定义由 SQL 步骤组成的有向无环图(DAG)工作流。PostgreSQL 在执行这些步骤时会进行持久化检查点。如果数据库崩溃、重启或某个步骤失败,执行将从最后一个持久化检查点恢复,而非从头开始。
适用场景与目标用户
- 后端与数据工程师:希望工作流与其操作的数据紧邻,避免跨系统维护状态。
- DBA 与 SRE:需要自动化运行手册(Runbooks),确保流程在重启后存活且可在 SQL 中审计。
- 数据/AI 管道团队:需要针对每一行、每个文档或每个批次实现持久化执行。
典型用例
- 向量嵌入管道:分块数据 -> 调用嵌入 API -> 使用
pgvector进行 upsert。 - 数据摄入管道:暂存、去重、转换并发布大批量数据。
- 计划维护:检测膨胀 -> 通知 -> 等待审批 -> 执行下一步。
- 扇出聚合:并行运行独立查询,然后连接结果。
- 外部 API 工作流:从 SQL 内部执行丰富化、分类和 Webhook 风格调用。
与传统方案的对比
- 替代
pg_cron+ 状态表:无需手动管理重试计数器、状态列和轮询工作进程。 - 替代外部编排器:无需引入 Airflow、Temporal、Step Functions 或 Argo 等重型外部服务。
- 替代队列+Worker+状态表:消除了协调重试和部分完成所需的复杂队列和状态表。
- 替代
plpgsql过程:解决了长事务或崩溃导致必须重头开始的问题。
技术实现与工作流定义
工作流定义以 SQL 形式呈现,使用组合操作符(如 ~> 和 |=>)。
- 定义:使用组合操作符定义步骤。
- 启动:通过
df.start()启动工作流并返回实例 ID。 - 执行:运行时在每个步骤之间进行持久化检查点。
- 监控:在运行期间或完成后,通过查询 PostgreSQL 表(如
df.instances)获取状态和结果。
代码示例:
SELECT df.start(
'SELECT id FROM documents WHERE processed = false LIMIT 100' |=> 'batch'
~> 'UPDATE documents SET processed = true WHERE id = ANY($batch)'
);
限制与边界
pg_durable 故意采用 SQL 形状的设计。以下场景不适合使用:
- 需要亚毫秒级同步请求处理。
- 无法安装扩展或运行后台工作进程的环境。
- 工作流主要位于 PostgreSQL 外部且跨越多个异构系统。
- 需要任意应用逻辑(非 HTTP SDK、非 SQL 映射的控制流)。
对于需要任意代码的步骤,建议将其封装为 SQL 函数,或通过 df.http() 暴露为 HTTP 端点,或将该部分逻辑交给通用编排器处理。
安装与配置
- 支持版本:PostgreSQL 17 和 18(amd64)。
- 构建依赖:Rust (nightly),
cargo-pgrx0.16.1。 - 安装方式:
- 从 GitHub Release 获取 Debian 包(如
pg-durable-postgresql-17_x.x.x-1_amd64.deb)。 - 将扩展库、控制文件和 SQL 升级文件安装到 PostgreSQL 目录。
- 在
postgresql.conf中将pg_durable添加到shared_preload_libraries。 - 重启 PostgreSQL。
- 在目标数据库中执行
CREATE EXTENSION pg_durable;。
- 从 GitHub Release 获取 Debian 包(如
权限与安全
CREATE EXTENSION不会向PUBLIC授予任何权限。- 管理员必须显式授予应用角色权限,使用
df.grant_usage('role')。 - 行级安全(RLS):确保每个用户只能查看和管理自己的持久化函数实例和节点。
- 后台工作进程角色:
pg_durable.worker_role(默认为azuresu)必须是超级用户,以绕过 RLS 管理所有用户的实例。 - 升级注意:升级扩展后,需重新运行
df.grant_usage以确保新函数的访问权限生效。
关键要点
- 零基础设施:作为 PostgreSQL 扩展运行,无需 Redis、Temporal 或其他外部服务。
- SQL 原生:使用组合操作符在 SQL 中定义函数,逻辑清晰且可审计。
- 数据库感知:提供调度、条件和并行执行的一等公民原语。
- 持久化:函数状态持久化到 PostgreSQL,能够承受崩溃、重启和故障转移。
- 状态内聚:重试状态、进度跟踪和检查点机制内置于数据库,消除了定制的应用代码。
- 运维简化:通过标准的 PostgreSQL 表(如
df.instances)提供操作可见性,沿用现有的认证和备份模型。 - 开发体验:支持通过 VS Code Dev Container 或本地
pg-start.sh脚本快速搭建开发环境。
意义与影响
pg_durable 的开源标志着数据库即服务(DBaaS)理念在功能层面的进一步延伸。它将原本分散在应用层、消息队列和外部编排器中的状态管理和容错逻辑,收拢回数据库内核。
- 简化架构:对于已经重度依赖 PostgreSQL 的团队,
pg_durable消除了维护复杂微服务架构(Cron + Worker + Queue + Status Table)的负担,降低了系统耦合度。 - 提升可靠性:通过将检查点机制下沉到数据库引擎,确保了在基础设施故障下的数据一致性和任务连续性,避免了“部分成功”导致的脏数据或重复处理。
- 推动 AI/数据管道标准化:随着 RAG 和向量数据库的普及,数据处理管道日益复杂。
pg_durable为在数据库内部构建可靠的 ETL 和 AI 预处理流水线提供了原生支持,特别契合pgvector等扩展生态。 - 性能与成本优化:减少了数据在应用层和数据库层之间的网络往返,以及跨系统协调的开销。对于中小规模团队,这意味更低的运维成本和更少的组件故障点。
总体而言,pg_durable 是微软“将计算靠近数据”战略的具体落地,它为 PostgreSQL 用户提供了一种更现代、更健壮的方式来处理长运行和容错型任务,填补了传统 SQL 过程语言与现代分布式编排系统之间的空白。
