pg_durable: 微软开源数据库内持久化执行
摘要
微软开源了pg_durable,这是一个PostgreSQL扩展,支持长时间运行的SQL函数的持久化执行,具有自动检查点和容错恢复功能。
查看缓存全文
缓存时间: 2026/06/05 17:09
microsoft/pg_durable
来源:https://github.com/microsoft/pg_durable
网站(https://microsoft.github.io/pg_durable/)· 文档· 快速示例· GitHub(https://github.com/microsoft/pg_durable)许可证
PostgreSQL 17 和 18(https://www.postgresql.org/)
PostgreSQL 内的持久化执行
为那些已经将状态保存在 Postgres 中,并希望不再拼凑 cron 任务、工作进程、队列和状态表来使后台工作变得可靠的团队提供长时间运行、容错的 SQL 函数。在 SQL 中定义工作流,让 pg_durable 对每一步进行检查点记录,并在崩溃、重启或步骤失败后恢复。持久化执行现在是一种标准的行业模式,pg_durable 将其引入 Postgres 内部,无需额外的基础设施服务。这是我们使命的一部分——让计算靠近数据。
这适合我吗?
适用人群
- 后端和数据工程师,希望工作流与所操作的数据共存。
- 数据库管理员和 SRE,需要自动化能够在重启后存活并以 SQL 形式审计的运行手册。
- 构建数据或 AI 管道的团队,需要按行、按文档或按批次的持久化执行。
核心理念
pg_durable 函数是一个由 SQL 步骤构成的图,PostgreSQL 会逐步执行并对其进行检查点记录。如果数据库崩溃、重启或某一步骤失败,执行将从最后一个持久化检查点恢复,而无需手动重建状态。
此类工作负载的适用场景
- 向量嵌入管道:分块、调用嵌入 API,然后更新插入到
pgvector中。 - 数据摄入管道:暂存、去重、转换并发布大批量数据。
- 计划性维护:检测膨胀、通知、等待批准,然后执行下一步操作。
- 扇出聚合:并行运行独立查询,然后合并结果。
- 外部 API 工作流:从 SQL 中进行数据丰富、分类和 webhook 风格的调用。
你当前可能采取的做法
pg_cron加上任务表、状态列、重试计数器和轮询工作进程。- 外部编排器(如 Airflow、Temporal、Step Functions 或 Argo)回调 Postgres。
- 队列加工作进程加独立的状态表来协调重试和部分完成。
- 一个
plpgsql过程,在崩溃或长时间运行的事务迫使你重新开始时失效。
它解决的问题
- 长时间任务中途重启意味着重复执行已成功完成的工作。
- 单行失败或单次 API 调用失败导致手动清理和不确定的重放。
- 长事务持有锁、增加 WAL,使批处理任务在较大规模下变得脆弱。
- 应用层的并行工作引入了更多部分失败错误和状态漂移的隐患。
- 工作流逻辑分散在 SQL、工作进程、队列、仪表盘和状态表中。
你架构中会发生的变化
- 工作流定义转移到 SQL 中,并以
df.start(...)开始。 - 重试状态、进度跟踪和检查点记录转移到 Postgres 中,而不是自建的应用代码。
- 部分应用层工作进程、队列消费者或调度粘合剂可以完全消失。
- 运维可见性来自 Postgres 表(如
df.instances),使用与数据相同的认证和备份模型。
何时不应使用
- 任务已经是单一的
INSERT ... SELECT或一条普通 SQL 语句。 - 你需要亚毫秒级的同步请求处理,而不是持久化的后台执行。
- 你无法在 Postgres 环境中安装扩展或运行后台工作进程。
- 工作流主要位于 Postgres 之外,并跨越许多异构系统。
- 你需要无法清晰映射为 SQL 步骤、分支、循环或 HTTP 调用的任意应用逻辑。
工作原理
- 在 SQL 中使用可组合的操作符(如
~>和|=>)定义工作流。 - 使用
df.start()启动工作流,并获取一个实例 ID。 - 让运行时在每一步之间通过检查点持久化执行每个步骤。
- 在工作流运行期间或完成后,从 PostgreSQL 查询状态和结果。
局限性
该模型有意采用 SQL 形式。如果某一步需要任意代码、非 HTTP 的 SDK 或丰富的内存控制流,你可能需要将该逻辑包装在 SQL 函数中、将其暴露为 df.http() 的 HTTP 端点,或针对系统的该部分使用通用编排器。
特性
- 持久化 — 函数状态持久化到 PostgreSQL。能够承受崩溃、重启和故障转移。
- SQL 原生 — 使用可组合的操作符在 SQL 中定义函数。
- 感知数据库 — 提供一流的原语用于调度、条件和并行执行。
- 零基础设施 — 作为 PostgreSQL 扩展运行。无需 Redis、Temporal 或外部服务。
快速示例
-- 一个按步骤处理数据的持久化函数
SELECT df.start(
'SELECT id FROM documents WHERE processed = false LIMIT 100'
|=> 'batch'
~> 'UPDATE documents SET processed = true WHERE id = ANY($batch)'
);
软件包
标记版本发布时会发布针对 PostgreSQL 17 和 18(amd64)的 Debian 软件包,这些包位于 GitHub 发布资产生成中。软件包命名为 pg-durable-postgresql-<版本>-1_<架构>.deb,并将扩展库、控制文件和 SQL 升级文件安装到相应的 PostgreSQL 安装目录中。
安装软件包后,将 pg_durable 添加到 shared_preload_libraries,重启 PostgreSQL,并在已配置的 pg_durable 数据库中创建扩展:
CREATE EXTENSION pg_durable;
默认的 pg_durable 数据库是 postgres;有关后台工作进程配置和权限设置,请参见用户指南。
发布资产生成还包括用于从源码构建的源码归档。
开发安装
先决条件
- PostgreSQL 17 或 18
- Rust(nightly)
- cargo-pgrx(https://github.com/pgcentralfoundation/pgrx)0.16.1
GitHub Codespace
主分支预构建会安装 PostgreSQL 17、构建 pg_durable,并在 ~/.pgrx 下准备一个包含扩展的本地集群。PostgreSQL 不会保持运行状态,请在开始工作时启动它。
# 启动 PostgreSQL
./scripts/pg-start.sh
# 连接
~/.pgrx/17.*/pgrx-install/bin/psql -h localhost -p 28817 -d postgres
在没有就绪预构建的分支上,运行 pg-start.sh——它会在首次运行时构建并安装扩展(预计需要几分钟):
./scripts/pg-start.sh
其他环境
本地开发和 Dev Container
VS Code Dev Container(.devcontainer/)预装了 Rust、cargo-pgrx 和 PostgreSQL 17。对于裸机本地机器,请先按照 .devcontainer/onCreateCommand.sh 中的步骤安装工具链。
# 构建、初始化 PostgreSQL 并安装扩展
# 这需要一些时间——可以先去忙别的事情
./scripts/pg-start.sh
# 连接到本地 pgrx PostgreSQL 实例
~/.pgrx/17.*/pgrx-install/bin/psql -h localhost -p 28817 -d postgres
pg-start.sh 会引导新的本地数据目录,创建一个 postgres 超级用户,并为当前 OS 用户创建一个匹配的超级用户角色,以便默认的本地 psql 使用继续正常工作。如果你想强制使用规范的引导角色,请使用 -U postgres。
Docker
# 构建并测试
./scripts/test-e2e-docker.sh --rebuild
# 可选:部署到 ACR(用于自定义内置 pg_durable 的 PG17 镜像)
./scripts/deploy-acr.sh
多用户设置
CREATE EXTENSION pg_durable 不会向 PUBLIC 授予任何权限。安装扩展后,管理员必须显式授予应用程序角色访问权限。行级安全性(RLS)确保每个用户只能看到和管理自己的持久化函数实例和节点。
向应用程序角色授予权限:
-- 在 CREATE EXTENSION 之后向特定角色授予权限
SELECT df.grant_usage('app_role');
或者,创建一个间接角色并将应用程序角色设为其成员:
-- 为 pg_durable 访问创建一个共享角色
CREATE ROLE pg_durable_user NOLOGIN;
SELECT df.grant_usage('pg_durable_user');
-- 将成员资格授予应用程序角色
GRANT pg_durable_user TO app_backend, etl_service;
有关完整的单个授权列表、撤销权限以及保护升级后的安装,请参见用户指南 — 权限授予部分。 注意:
GRANT EXECUTE ON ALL FUNCTIONS仅适用于授权时存在的函数。在通过ALTER EXTENSION pg_durable UPDATE升级 pg_durable 后,重新运行df.grant_usage('role')(或重新发出手动授权),以便新函数可访问。
关键点:
- 后台工作进程角色(
pg_durable.worker_roleGUC,默认值:azuresu)必须是超级用户——它绕过 RLS 来管理所有用户的实例。 - 用户对
df.instances/df.nodes拥有SELECT+INSERT权限,对实例的df.cancel()操作拥有列级UPDATE (status, updated_at)权限。 - 标识列(
submitted_by)用户无法修改。 df.vars使用每个用户的作用域 — 每个用户通过owner列和 RLS 拥有自己的变量命名空间。超级用户绕过 RLS,但 DSL 函数仍然通过显式过滤器将作用域限制到调用用户。避免在明文中存储密钥。
持续集成
所有拉取请求在合并前必须通过以下检查:
- 格式检查 —
cargo fmt --check - Clippy 和测试 —
cargo clippy、单元测试(cargo pgrx test pg17)、pg_regress 测试和 E2E 测试
CI 工作流定义在 .github/workflows/ci.yml 中。它使用 pgrx 下载和管理 PostgreSQL。
测试
pg_durable 有两个测试套件:
pg_regress 测试(标准 PostgreSQL 回归测试)
使用 PostgreSQL 的标准测试框架进行快速、确定性的核心 DSL 功能测试。测试 SQL 位于 sql/,预期输出位于 expected/,PGXS 在根 Makefile 中配置。
make test-regress # 完全重置并运行
make installcheck # 仅运行(PostgreSQL 必须已运行)
E2E 测试(综合场景测试)
使用 pgrx PostgreSQL 进行复杂的本地集成测试:
./scripts/test-e2e-local.sh # 所有本地 SQL E2E 测试,包括特殊的重启/配置阶段
./scripts/test-e2e-local.sh 04_parallel # 特定测试
./scripts/test-e2e-local.sh --default-build-phases # 仅 default-build 阶段组
详情请参见 tests/e2e/。
文档
架构
pg_durable 是一个 PostgreSQL 扩展(使用 pgrx(https://github.com/pgcentralfoundation/pgrx)构建)——所有内容都在 PostgreSQL 服务器内运行,无需外部服务。该扩展公开了一个用于构建函数图的 SQL DSL,并注册了一个后台工作进程,该工作进程在两个更低层的 Rust 库之上持久地执行这些函数:
- duroxide(https://github.com/microsoft/duroxide) — 一个持久化任务框架,提供编排运行时(确定性重放、检查点、子编排、定时器)。
- duroxide-pg(https://github.com/microsoft/duroxide-pg) — 一个基于 PostgreSQL 的状态提供程序,用于 duroxide。它将运行时状态(实例、历史记录、工作队列)持久化在扩展拥有的专用
duroxide.*模式中。
┌────────────────────────────────────────────────────────────────────┐
│ PostgreSQL │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ pg_durable 扩展 (pgrx) │ │
│ │ │ │
│ │ SQL DSL 'sql' |=> 'name' ~> 'sql2' │ │
│ │ df.if() | df.join() | df.loop() │ │
│ │ │ │
│ │ 后台工作进程(在进程中托管 duroxide 运行时) │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ duroxide(编排运行时) │ │ │
│ │ │ ┌──────────────────────────────────────────────────┐ │ │ │
│ │ │ │ duroxide-pg(PostgreSQL 状态提供程序) │ │ │ │
│ │ │ └──────────────────────────────────────────────────┘ │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ 模式 │
│ df.* DSL 图(节点、实例、变量) │
│ duroxide.* 运行时状态(由 duroxide-pg 拥有) │
└────────────────────────────────────────────────────────────────────┘
如果你更愿意用 Rust、Python 或 Node 编写持久化函数,同时仍然将状态持久化到 PostgreSQL,你可以直接从宿主语言中使用 duroxide 和 duroxide-pg——pg_durable 是在这对工具之上构建的,适合你更愿意用 SQL 编写的情况。
状态
预览版 — 该项目目前处于预览阶段。
支持
请使用 GitHub Issues 报告错误和提出功能请求。不要通过公开的 GitHub Issues 报告安全漏洞;请按照 SECURITY.md 中的说明操作。
行为准则
该项目已采用 Microsoft 开放源代码行为准则(https://opensource.microsoft.com/codeofconduct/)。有关更多信息,请参阅行为准则常见问题解答(https://opensource.microsoft.com/codeofconduct/faq/),或通过 [email protected] 联系。
安全性
Microsoft 非常重视我们软件产品和服务的安全性。请不要通过公开的 GitHub Issues 报告安全漏洞。有关安全报告说明,请参见 SECURITY.md。
隐私与遥测
pg_durable 不会向 Microsoft 发送遥测数据。
商标
本项目可能包含项目、产品或服务的商标或徽标。授权使用 Microsoft 商标或徽标必须遵守且遵循 Microsoft 的商标与品牌指南(https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general)。在修改版项目中使用 Microsoft 商标或徽标不得引起混淆或暗示 Microsoft 赞助。任何第三方商标或徽标的使用均须遵守其各自政策。
许可证
PostgreSQL 许可证
相似文章
持久化执行:硬核方式
一本教程指南,教你如何受Kubernetes the hard way启发,从零开始使用Go和Postgres构建持久化执行引擎。
PgDog 获得融资,即将登陆您的数据库
PgDog 是一个开源代理,使 Postgres 实现水平扩展,已从 Basis Set、YC 等机构获得 550 万美元融资。该工具已在生产环境中每秒处理超过 200 万次查询。
PgDog
PgDog 是一款无需修改应用程序即可扩展 PostgreSQL 的工具,提供连接池和负载均衡功能。
DuckPGQ – 一个用于图工作负载的DuckDB社区扩展
DuckPGQ 是一个 DuckDB 社区扩展,它为 DuckDB 增加了 SQL/PGQ 标准图查询能力,从而在分析工作流中实现高性能图分析。
pgBackRest 将继续发展
pgBackRest,一款流行的 PostgreSQL 备份工具,宣布将在一系列赞助商(包括 Amazon Web Services、Supabase 等)的支持下继续开发,确保长期可持续性。