持久化工作流:直接用 Postgres
速览
该资讯探讨了将 PostgreSQL 作为持久化工作流存储后端的技术优势。Postgres 提供的事务保证和 ACID 特性,使其能够可靠地处理复杂的工作流状态管理。这种方法简化了架构,避免了引入额外的分布式状态存储系统。
AI 深度解读
Just Use Postgres for Durable Workflows:用数据库替代外部编排器
背景
持久化工作流(Durable Workflows)是一种构建可靠程序简单而强大的工具。其核心思想是:在程序运行过程中,定期将其进度检查点(checkpoint)保存到数据库中。这样,如果程序崩溃或失败,可以从最后一个检查点重新加载,从而从最后完成的步骤恢复执行。这类似于电子游戏中的“存档”机制:定期保存进度,以便在崩溃时“读档”恢复。
目前,持久化工作流主要通过**外部编排器(External Orchestration)**来实现。这是 Temporal、Airflow 和 AWS Step Functions 等系统采用的模式。在这种模型中,持久化程序被编写为一系列步骤的工作流,其执行由中央编排器协调。
当客户端提交一个工作流时,编排器在数据存储中为其创建记录,然后将其分派给工作器(Worker)执行。每当工作器完成一个步骤,它会将结果发送回编排器。编排器在数据存储中检查点保存输出,然后分派下一步。如果工作器崩溃或失败,编排器会将工作流分派给另一个工作器,并从其最后一个检查点步骤开始执行。
然而,这种架构引入了额外的复杂性和单点故障风险。
核心内容
本文主张,外部编排器从根本上来说是过度复杂的。持久化工作流的核心在于将程序状态检查点保存到数据库中。既然持久化工作流关乎数据库,那么就没有理由拥有一个单独的编排器服务器。相反,直接使用数据库本身作为编排器会更简单、更高效。为了具体说明这一点,文章聚焦于在 Postgres 上构建持久化工作流,因为其普及度、可扩展性和丰富的生态系统使其成为理想选择。
基于 Postgres 的架构设计
在基于 Postgres 的持久化工作流系统中,应用服务器直接与 Postgres 通信以执行工作流,而不是通过中央编排器。
- 提交与执行:客户端通过在 Postgres 的
workflows表中创建条目来提交工作流。应用服务器轮询该表以出队(dequeue)并执行工作流。 - 检查点保存:服务器在执行工作流时,将每个步骤的输出检查点保存到 Postgres。
- 故障恢复:如果执行工作流的服务器崩溃或失败,另一台服务器可以从检查点恢复其工作流。
去中心化协调机制
这种设计使得中央编排器变得不必要,因为应用服务器可以通过 Postgres 进行协调:
- 工作流分派:服务器不再依赖中央编排器将工作流分派给工作器,而是合作地从 Postgres 表中出队工作流。利用锁定子句(locking clauses)等机制,确保每个工作流仅由一个工作器出队。
- 检查点保存:工作器直接向 Postgres 检查点保存步骤,而不是依赖编排器。
- 冲突检测:如果多个工作器尝试同时执行相同的工作流,Postgres 数据库完整性约束允许它们在检查点时检测到重复工作并退避(back off)。
优势分析
用 Postgres(或其他数据库)替换中央编排器,使持久化工作流从根本上变得更简单。特别是,可扩展性、可用性、可观测性和安全性等难题可以使用成熟的 Postgres 原生解决方案来解决。
1. 可扩展性与可用性(Scalability and Availability)
基于数据库的持久化工作流系统的可扩展性和可用性从根本上取决于底层数据库。
- 水平扩展:系统可以通过添加更多工作器服务器进行水平扩展,其最大容量由数据库处理工作流的速度决定。
- 高可用性:工作器是可互换的,可以自由恢复彼此的状态,因此只要底层数据库可用,系统就是可用的。
针对 Postgres 的具体优势:
- 可扩展性:单个 Postgres 服务器可以垂直扩展,每秒处理数万个工作流。进一步扩展可以通过分布式(如 CockroachDB)或分片 Postgres 实现。
- 可用性:Postgres 支持带有自动故障转移的流复制,托管服务开箱即用地提供多可用区(Multi-AZ)部署和高可用性 SLA。这意味着数十年在大规模运营 Postgres 方面的工程工作和研究可以直接转化为运营持久化工作流的能力。
2. 可观测性(Observability)
在基于 Postgres 的持久化执行中,工作流及其步骤被检查点保存到 Postgres 表中。这意味着可观测性是内置的:你可以扫描这些检查点以实时监控工作流并可视化执行过程。
Postgres 在此方面表现出色,因为几乎所有工作流可观测性查询都可以用 SQL 表达。例如,查找上个月出错的所有工作流的查询可能如下:
SELECT * FROM workflow_steps
WHERE status = 'ERROR'
AND created_at > NOW() - INTERVAL '1 month';
这种能力非常强大。它之所以可能,是因为 Postgres 的关系模型允许你以声明式方式在 SQL 中表达复杂的过滤和分析操作,利用了几十年的查询优化研究。许多具有更简单数据模型的系统(如流行外部编排器使用的键值存储)不支持此类功能。通过将工作流和步骤数据存储在 Postgres 表中,并使用二级索引增强以进行快速分析查询,你可以“免费”获得高效的持久化执行可观测性。
3. 可靠性与安全性(Reliability and Security)
- 外部编排器的风险:当使用外部编排器进行持久化执行时,编排器及其数据存储都是单点故障。因为它们直接协调工作流执行,如果其中任何一个停机,整个应用程序将不可用。此外,由于它们处理和存储工作流及步骤检查点,它们很可能访问敏感的应用程序数据,因此必须像其他敏感基础设施一样进行加固、访问控制和审计。
- Postgres 的优势:相比之下,基于 Postgres 的持久化执行的唯一故障点是 Postgres 本身,所有工作流数据直接存储在 Postgres 中,从不经过任何其他系统。如果应用程序已经依赖 Postgres,采用持久化执行不会向系统添加任何新的故障点,也不会引入新的安全表面。数据库已经是关键基础设施,因此重用它们进行编排比为其添加新的关键基础设施更有意义。
关键要点
- 简化架构:持久化工作流的核心是状态检查点,无需额外的中央编排器服务器,直接使用数据库(如 Postgres)作为编排器可以显著降低系统复杂度。
- 去中心化协调:应用服务器通过数据库的锁定机制和完整性约束自行协调工作流的出队、执行和冲突检测,消除了对中央控制节点的依赖。
- 利用现有基础设施:如果系统已使用 Postgres,直接复用其可扩展性、高可用性和安全性能力,避免引入新的单点故障和安全攻击面。
- 原生可观测性:由于数据直接存储在关系型数据库中,可以使用标准 SQL 进行实时查询和分析,无需额外的日志聚合或监控管道。
- 成熟的技术栈:Postgres 经过数十年大规模运营验证,其流复制、自动故障转移和分片方案为持久化工作流提供了坚实的基础。
意义与影响
这篇文章代表了一种回归基础的系统设计哲学:避免过度工程化。在微服务和分布式系统盛行的今天,许多团队倾向于引入复杂的编排工具(如 Temporal 或 Airflow)来处理工作流。然而,对于许多场景而言,这种复杂性并非必要。
对开发者的意义:
- 降低运维负担:无需维护额外的编排器集群、监控其健康状态或处理其故障。
- 简化数据一致性:工作流状态与业务数据共存于同一数据库,避免了跨系统数据同步和一致性问题。
- 提升调试效率:直接查询数据库即可了解工作流状态,无需学习特定的编排器 API 或查询语言。
对行业的影响:
- 数据库即平台(Database as a Platform):这一趋势强化了数据库作为应用核心逻辑承载者的角色。Postgres 不再仅仅是数据存储,而是通过扩展(如 DBOS 提供的框架)成为应用逻辑的执行环境。
- 成本优化:减少中间件层可以降低基础设施成本和许可费用。
- 可靠性提升:通过消除单点故障(编排器),系统整体可用性取决于数据库本身的 SLA,而数据库的高可用方案通常比自定义编排器更成熟和可靠。
总之,对于大多数不需要极端复杂编排逻辑的场景,"Just Use Postgres
