- 引言 — "用 Rust 重写了 Postgres"这个标题
- 通过四万六千个查询意味着什么 — 这个里程碑为何货真价实
- "100% 通过"没有证明的东西
- 性能数字,以及代码由 AI 写成这一点
- 结语 — 引擎,以及它之外的一切
- 参考资料
引言 — "用 Rust 重写了 Postgres"这个标题
Malcolm Matis(GitHub malisper)公开了 pgrust。一句话介绍很简单 — "A Postgres rewrite in Rust"。而标题更为震撼:100% 通过 Postgres 的回归测试(regression test)。这条登上 GeekNews 和 Hacker News 榜首的消息,同时引发了两种截然相反的反应 — "Postgres 终于用 Rust 写了?"和"用 AI 几周就写出来的数据库,谁敢把它放到生产环境?"。
本文想让这两种情绪都冷静下来。我们诚实地看看 pgrust 实际 做到了什么,以及"100% 通过回归测试"这句话意味着什么、又 不 意味着什么。先从事实说起:pgrust 以兼容 Postgres 18.3 为目标,在四万六千多个回归查询上给出与 Postgres 一致的输出。由于磁盘格式兼容,它能 直接在既有的 18.3 数据目录上启动。而且作者本人明确地说 — 它还没有为生产环境做好准备,也没有做性能优化,与既有的扩展(extension)也不兼容。
通过四万六千个查询意味着什么 — 这个里程碑为何货真价实
不要小看 Postgres 的回归测试套件。这套由 make check 驱动的测试是数十年打磨出来的资产,用四万六千多个查询扫过解析器、规划器、执行器、类型系统、内置函数,以及夹在其间的无数边界情况。通过标准并不宽松 — 必须 与期望输出逐字节一致。哪怕数字格式差一点、错误消息措辞错一个字,都算失败。
pgrust 把这一切都对齐到 Postgres 18.3,并且声称连验证受调度并发的 isolation 测试 也一并通过。在此之上还叠加了磁盘兼容性。能在真实的 18.3 数据目录上启动,意味着它真正理解了磁盘上的页面格式和目录(catalog)结构 — 这是一个信号,表明它不是只模仿了一部分 SQL 的玩具。
凡是从零重写过哪怕一个 SQL 解析器的人都知道,边界情况的长尾有多长。全流水线在四万六千个查询上与 Postgres 达成一致,意味着在极其广阔的表面积上复现了行为。这是一个真正的里程碑,不该被低估。
"100% 通过"没有证明的东西
问题在于,人们把这句话读成了"可以替代生产环境的 Postgres"。这误解了回归测试套件所验证的对象。回归测试 主要是针对单会话、确定性查询行为 的兼容性预言机(oracle)。它并不能证明以下这些:
- 持久性与崩溃恢复。 测试套件不会在写入过程中打出
kill -9,也不验证 WAL 重放、撕裂页(torn page)恢复、断电时的fsync语义。作者本人也在 HN 上表示,堆管理和持久性是"最终想要修复的部分",并回答说存储方面正在考虑将来引入OrioleDB。 - 实战并发下的 MVCC。 isolation 测试处理的是有剧本的调度。真实负载下的对抗性并发、长时间运行的事务、vacuum 与膨胀(bloat)的相互作用,都在它的覆盖范围之外。
- 长尾。 扩展以及
PL/Python、PL/Perl、PL/Tcl之类的过程式语言,目前还不兼容(作者已明说)。复制、逻辑解码、FDW,以及支撑运维的整个生态系统,都还缺席。
而且方法论很重要。一直修改直到测试变绿的 AI 循环,有可能收敛到 不是一般意义上的正确,而是针对测试的特殊处理(special-casing)。一条 HN 评论这样总结自己的经历 — 测试全部漂亮地通过了,可重写出来的东西本身却在基本功能上就是坏的。这正应了那句老话:"不存在完备的测试套件。"100% 通过的意思是"在测试过的查询上没有已知的不一致",而不是"没有 bug"。这么说的不只是批评者 — 是作者本人先钉下了话:它既没为生产环境准备好,也没做性能优化。
性能数字,以及代码由 AI 写成这一点
README 也提出了性能主张 — 在事务型负载上比 Postgres 快 50%,在分析型负载上快约 300 倍(不过比 ClickHouse 慢 2 倍)。听上去很惊人,但需要和 同一份 README 里写着的"尚未做性能优化" 放在一起来看。HN 上也有人对方法论表示怀疑 — 测量时 fsync 是不是开着的,以及拿它和为列式存储打磨了多年 SIMD 的 ClickHouse 相比,本来就是拿苹果比橘子。这些数字往好里说,也只能当作方向性参考来读才稳妥。
即便如此,用 Rust 重写这个想法本身仍然很有意思。内存安全性顺带就有了,而且与 每连接一进程 的 Postgres 不同,pgrust 选择了 每连接一线程 的模型,为并行性打开了空间。作者在有限的语境里也举出过一些数字,比如单个查询快 3 倍、正则表达式快 10 倍。
它是怎么造出来的,是另一个核心。据作者的开发记,大约两周里生成了 约 25 万行 Rust,在那个时间点通过了回归套件的约三分之一。他先用 Codex 编写单个功能,随后把编码智能体并行开到 最多 17 个,"一直推到 CPU 触及极限"。他在 HN 的回复中透露,起步方式是用 c2rust 做机器翻译、再把 unsafe 代码逐步清理掉,并用被赋予专用技能的 Claude 把移植工作并行化。也就是说,"用 Rust 重写"在一定程度上更接近"先翻译、再重写" — 在速度上固然惊人,但这同时也意味着 生成出来的未优化代码很多。
它难在哪里很清楚。数十年积累的 Postgres 边界情况、MVCC、磁盘格式、扩展的 ABI。回归套件之所以能充当标杆(bar),恰恰是因为那些边界情况用别的方法根本看不见。
结语 — 引擎,以及它之外的一切
总结起来是这样。100% 通过回归测试是一个真正令人印象深刻的里程碑,对于"让 Postgres 更容易从内部改造"这个目标而言,也是一件出色的研究工具。但它并不是"可直接替换的生产级 Postgres"。两者之间的差距,大多由那些并不光鲜的部分填满 — 持久性、复制、备份、升级、运维工具 — 而这道差距是以年计的。
在这一点上,它自然而然地与我那篇 CNPG 故障转移实测文章 接上了。生产级 Postgres 不只是查询引擎。它是复制与故障转移、备份、滚动升级,以及把这一切自动化的 operator 生态系统。在那篇文章里,我杀掉一个真实的 Postgres 主库,实测到副本在 23.1 秒 内无损失地被提升为主库。一个才诞生几周的引擎还没能养出来的,正是那套"引擎之外的脚手架(scaffolding)"。pgrust 在语言表面(language surface)上赢了,而生产环境赢在生存能力上。两者都为真。
所以我一边为 pgrust 加油,一边把标题当标题来读。用 Rust 重写 Postgres 这个实验,完全值得一看 — 只是,一旦把它读成"现在可以把生产环境的 Postgres 换掉了",那就等于跳过了作者亲手写下的那三行警告。
参考资料
현재 단락 (1/23)
Malcolm Matis(GitHub `malisper`)公开了 **pgrust**。一句话介绍很简单 — "A Postgres rewrite in Rust"。而标题更为震撼:**100...