在 Postgres 上构建持久化工作流
- #Postgres
- #持久化工作流
- #系统设计
- #Hacker News
- #dbos.dev
持久化工作流是构建可靠程序的简单而强大的工具。其核心思想是:程序运行时,定期将进度检查点保存到数据库。这样,如果程序崩溃或失败,可以从最后一个检查点恢复,从已完成的上一步继续执行。你可以将其类比为游戏存档:定期“保存”程序进度,以便崩溃时从最后一个存档点“加载”。
通常,持久化工作流通过外部编排实现,如 Temporal、Airflow 和 AWS Step Functions 使用的模式。在此模型中,持久化程序被编写为由中央编排器协调执行步骤的工作流。客户端提交工作流时,编排器在数据存储中创建记录,然后分发给工作节点执行。每当工作节点完成一步,就将结果发送回编排器,编排器检查点输出到数据存储,再调度下一步。如果工作节点崩溃,编排器将工作流分发给另一个工作节点,从最后一个检查点开始执行。
本文认为外部编排本质上过于复杂。持久化工作流的核心是将程序状态检查点到数据库。如果持久化工作流与数据库相关,那么就没有必要使用单独的编排服务器。相反,使用数据库本身作为编排器更简单、更高效。为了更具体,我们将重点放在 Postgres 上构建持久化工作流,因为它的流行性、可扩展性和丰富的生态系统使其成为理想选择。
在基于 Postgres 的持久化工作流系统中,应用服务器直接与 Postgres 通信以执行工作流,而不是通过中央编排器。客户端通过在 Postgres 工作流表中创建条目来提交工作流。应用服务器轮询该表以取出工作流并执行。服务器执行工作流时,将每一步的输出检查点到 Postgres。如果执行工作流的服务器崩溃,另一台服务器可以从检查点恢复工作流。
这种设计使中央编排器变得不必要,因为应用服务器可以通过 Postgres 协调。服务器无需依赖中央编排器分发工作流,而是通过锁定子句等机制协作地从 Postgres 表中取出工作流,确保每个工作流只被一个工作节点取出。工作节点自己将步骤检查点到 Postgres,而不是依赖编排器。如果多个工作节点同时尝试执行同一工作流,Postgres 的数据库完整性约束可以让它们在检查点时检测到重复工作并回退。
用 Postgres(或其他数据库)替代中央编排器使持久化工作流从根本上更简单。特别是,可扩展性、可用性、可观测性和安全性等难题可以通过成熟的 Postgres 原生解决方案来解决。
可扩展性与可用性
数据库支持的持久化工作流系统的可扩展性和可用性根本上取决于底层数据库。通过添加更多工作节点服务器可以实现水平扩展,因此最大容量由数据库处理工作流的速度决定。同样,工作节点可互换,可以自由恢复彼此的状态,因此只要底层数据库可用,系统就可用。
使用 Postgres 特别有益,因为其可扩展性和可用性已有充分研究并有可靠的解决方案。在可扩展性方面,单个 Postgres 服务器可以垂直扩展以处理每秒数万个工作流,进一步扩展可以通过使用分布式(如 CockroachDB)或分片 Postgres 实现。在可用性方面,Postgres 支持带有自动故障转移的流复制,托管服务提供多可用区部署和高可用性 SLA。因此,在规模上运维 Postgres 的数十年工程工作和研究可以直接转化为运维持久化工作流。
可观测性
使用 Postgres 支持的持久化执行时,工作流及其步骤被检查点到 Postgres 表。这意味着可观测性是内置的:可以扫描这些检查点以实时监控工作流并可视化执行。Postgres 擅长此道,因为几乎所有工作流可观测性查询都可以用 SQL 表达。例如,查找上个月所有出错工作流的查询:
SELECT * FROM workflows WHERE status = 'error' AND created_at > NOW() - INTERVAL '1 month';
这样的查询看似简单,但其强大之处难以言表。只有 Postgres 的关系模型允许你用 SQL 声明性地表达复杂的过滤和分析操作,利用数十年的查询优化研究。许多具有更简单数据模型的系统(如流行的外部编排器使用的键值存储)不支持这一点。通过将工作流和步骤数据存储在 Postgres 表中,并辅以用于快速分析查询的二级索引,你可以“免费”从持久化执行中获得高效的可观测性。
可靠性与安全性
使用外部编排器进行持久化执行时,编排器及其数据存储都是单点故障。由于它们直接协调工作流执行,任何一个宕机都会导致整个应用不可用。此外,由于它们处理和存储工作流及步骤检查点,可能访问敏感应用数据,因此必须像其他敏感基础设施一样进行加固、访问控制和审计。相比之下,Postgres 支持的持久化执行中唯一的故障点是 Postgres 本身,所有工作流数据直接存储在 Postgres 中,不会经过任何其他系统。如果应用已经依赖 Postgres,采用持久化执行不会给系统增加新的故障点,也不会引入新的安全面。数据库已经是关键基础设施,因此将其复用于编排比添加新的关键基础设施更有意义。
了解更多
如果你喜欢构建可扩展、可靠的系统,我们很乐意与你交流。在 DBOS,我们的目标是使基于 Postgres 的持久化执行尽可能简单和高效。查看: 快速入门:https://docs.dbos.dev/quickstart GitHub:https://github.com/dbos-inc Discord 社区:https://discord.gg/eMUHrvbu67
评论