近日,由 Open Source Hong Kong(开源香港)主办的月度开发者沙龙在香港顺利落幕。瀚高股份资深 PostgreSQL 内核研发专家、PG 19 版本核心贡献者 周煦能受邀带来全英文主题演讲《 The Hitchhiker’s Guide to PostgreSQL Hacking: Don’t Panic, Just Start Small》。
针对广大开发者“想参与 PG 开源贡献、却苦于代码库庞大、社区门槛高无从下手”的普遍难题,本次分享给出了一套新手友好、可落地、循序渐进的开源贡献方法论,从心态、入门路径、社区工作流到真实内核案例,完整拆解从零到一的 PostgreSQL 黑客成长之路。
以下为本次演讲完整精华实录。
PostgreSQL 是全球最先进的开源关系数据库之一,其代码库庞大、功能复杂,参与社区开发常令初学者望而生畏。本文基于一场面向 PostgreSQL 潜在贡献者的技术演讲,系统梳理了从零开始参与 PostgreSQL 社区贡献的可行路径,涵盖心理准备、入门策略、补丁审查工作流,并借助一个真实案例(
WAIT FOR LSN 功能的开发与审查)展示“小步启动”如何演变为对核心内幕的深入理解。
无论你是出于技术兴趣、社区情怀,还是职业发展考虑,本文都将帮助你找到第一个可落地的切入点。
每一位新人的 PostgreSQL 黑客之旅往往伴随着复杂的心情——兴奋、好奇、可能性,同时也夹杂着自我怀疑、不确定和困惑。这完全正常。从外部看,PostgreSQL 似乎已经“完成”且令人畏惧;但走近看,它依然是一个活生生的工程产品,人们在其中提问、修正补丁、改变主意。
承认这一点很重要: Hacking on Postgres 确实很难。代码库规模巨大且复杂,仅找到起点就是一道难题;审查过程严格甚至挑剔,补丁作者必须考虑众多边界情况;而数据库技术本身——优化器、事务、并发控制、复制、存储、崩溃恢复——全是硬核系统话题。
既然如此,为何仍有人乐此不疲?动机通常来自三个维度:
这三种动机并不互斥,你可以同时享受技术挑战、帮助社区并构建职业价值。
不要试图一开始就理解全部。 从足够小、能完成的任务开始,以此建立信心和熟悉度。常见的三个切入点包括:
这三个路径的共同点是:都给你一个 具体的研究对象——某个补丁、某个 bug、某个测试失败或某种行为。
在众多起点中,演讲者最推荐的是
从审查补丁开始。直接贡献新特性难度较高,而审查现有代码能让你逐步熟悉
pgsql-hackers 社区文化、隐性的编码规范以及不成文的沟通惯例。一份有用的审查不要求完美——你可以报告补丁能构建、测试某个边界情况、指出混淆的错误信息,或询问某行为是否为预期。
订阅 pgsql-hackers 邮件列表是进入社区的第一步,这里是官方讨论、技术决策、补丁评审的核心阵地。新手无需急于发言,优先通过长期阅读,观察社区讨论逻辑、论证方式与评审标准,逐步建立社区语境认知。
开发者可通过 PostgreSQL 官方 CommitFest 补丁队列挑选适配自身能力的补丁,优先选择逻辑清晰、改动范围可控的内容开展学习与评审。
审查过程建议遵循由浅入深的四个层次,从基础现实检查逐步上升到设计与可维护性:
--enable-cassert 构建实例,以便捕获内存假设错误,快速失败。make check 针对现有及新增回归测试套件。架构审查需要品味和上下文,但初学者仍可从简单问题开始:这是否重复了现有机制?测试是否描述了用户可见的行为?文档是否解释了语义?
演讲者从浏览邮件列表开始,注意到一个关于“实现等待 WAL LSN 重放”的讨论。起初这只是一个很具体的功能,却成为理解 PostgreSQL 内部机制的绝佳入口。
核心问题是在 异步流复制环境下的 写后读一致性。设想用户向主库写入一条评论,获得插入成功,然后立即从备库读取。由于复制是异步的,备库可能尚未重放该 WAL 记录,于是读操作可能返回空结果——从用户视角看,数据似乎丢失了。数据库自身行为正确,但用户体验却是“写入丢失”。
在流复制中,主库后端修改表并写入 WAL,WAL sender 将 WAL 发送给备库;备库上 WAL receiver 写入 WAL,startup 进程重放 WAL 到表中。异步场景下,后端在 WAL 本地刷盘后即可返回成功,而无需等待备库重放完成。因此存在多个位置概念:生成(generated)、发送(sent)、接收(received)、刷盘(flushed)、重放(replayed)。它们相关但保证不同。对于备库上的写后读可见性, 重放是关键——仅接收或刷盘都不够,因为表数据要等到重放应用该记录后才会更新。
在
WAIT FOR LSN 出现之前,常见解决方案是轮询:
pg_current_wal_insert_lsn() 获取目标 LSN。pg_last_wal_replay_lsn(),直到追上目标。轮询的吸引力在于实现简单,无需新 SQL 命令或新等待基础设施,只需在应用层写一个循环。但简单性的代价是反复支付,且开销发生在并非核心问题的地方。核心问题仅是比较目标 LSN 与备库重放进度,轮询却将其转化为大量 SQL 往返、连接管理和内核唤醒。
其开销有两方面:
常见的误解是“轮询很便宜,因为
pg_last_wal_replay_lsn() 只是简单的元数据读取”。但实际性能剖析显示,真正的 LSN 检查仅占 CPU 时间的约
1.6%,剩余开销来自 PL/pgSQL、SPI(服务器编程接口)、执行器、内核唤醒等“机械”开销。主要驱动因素包括:解释器调度开销、计划验证、SPI 结果处理、快照管理以及等待事件。轮询方案在 PG18 中的硬件指标(以 10 秒间隔测试)显示,其 cycles、instructions、cache misses 和 task-clock 均显著高于后续的等待方案。
WAIT FOR LSN 的流程更直接:
pg_current_wal_insert_lsn() 捕获插入 LSN。WAIT FOR LSN '<LSN>',等待该 LSN 重放完成。该方案避免了重复轮询带来的表达式求值开销、高频时钟检查,改为利用服务器自身的等待基础设施进行高效睡眠与唤醒。硬件对比(PG18 轮询 vs PG19 等待)显示,等待方案在 cycles(约低 10 倍)、instructions(约低 5 倍)、cache misses(约低 7 倍)和 task-clock(约低 3 倍)上均有显著改善。这种性能对比证据在审查中极具说服力,因为它将设计与测量联系起来,为其他开发者提供了可评估和挑战的具体数据。
技术实现只是故事的一部分。PostgreSQL 补丁通过社区反馈不断演进。
社区反馈指出命令需要
timeout 和
no_throw 选项,以便应用控制等待时长及超时行为。随后语法设计成为议题——遵循 PostgreSQL 惯例,使用
WITH (utility_option_list) 形式的选项列表,确保一致性及未来可扩展性。
最初,
WAIT FOR LSN 仅支持等待“重放”模式,以实现强一致性。但社区成员指出,某些用户或集群方案可能只需要等待 WAL 被“接收”或“刷盘”即可,这些较弱的一致性保证在特定耐久性需求下仍有价值。这一反馈改变了命令的抽象边界——不再是“等待备库可见”,而是“等待 LSN 达到选定的进度状态”。
最终语法演变为:
WAIT FOR LSN '<lsn>' [ WITH ( MODE '<mode>', timeout '...', ... ) ]
支持的 mode 包括:
standby_replay(默认):等待 WAL 重放至指定 LSN。standby_write:等待 WAL 在备库上被写入(接收)。standby_flush:等待 WAL 在备库上刷盘。primary_flush:等待 WAL 在主库上刷盘。这个设计保持了命令的通用性,避免为每个级别单独发明新命令,同时保留了原始用例(写后读一致性),并扩展了相邻场景。
回顾这段旅程,可以提炼出几点核心经验:
正如 Paul Graham 所说:“知识是分形扩展的,从远处看边缘光滑,但一旦学得足够多而靠近它,就会发现满是缝隙。” PostgreSQL 内核亦是如此。每次深入一个点,都会发现新的未知领域,但也正是这种发现推动着成长。
对于 PostgreSQL 黑客之路,永远没有“终点”,只有持续的开始。从一个审查、一个 bug、一个测试或一个小补丁起步,追随讨论,学习周边代码,让知识复合增长。
最重要的是——不要恐慌,从小处着手。
作为深耕开源数据库国产化的标杆企业,瀚高股份长期扎根 PostgreSQL 全球开源生态,是 PG 国际社区亚太地区核心贡献者。公司累计向社区提交超150万行代码、4000余篇技术文章,完成1100余项 Patch 迭代与 Bug 修复,持续助力社区版本迭代演进。同时,瀚高发起的 IvorySQL 开源项目已捐赠至开放原子开源基金会,以长期、稳定、持续的开源投入,向全球展现中国基础软件企业的技术沉淀与生态担当。
本次香港开源之夜分享,是瀚高链接国际化开源社区、赋能开发者成长的重要实践。未来,瀚高将持续深耕数据库内核技术创新,深度参与全球开源社区共建,持续输出国产技术方案与实战经验,搭建海内外开源技术交流桥梁,助力更多开发者走进开源、深耕开源、受益开源。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70043484/viewspace-3176513/ ,如需转载,请注明出处,否则将追究法律责任。