当高并发遇上锁机制,PostgreSQL 的“可扩展性天花板”再度被推上风口浪尖

近日,一条来自数据库技术圈的动态迅速引发开发者与架构师社区的广泛讨论——知名数据库专家、PostgreSQL 内核贡献者在一场技术分享中直言:“Postgres locks do not scale”(PostgreSQL 的锁机制无法随规模扩展)。这一论断犹如一枚深水炸弹,让原本平静的技术社区重新聚焦于这个老生常谈却始终未解的核心问题。

导语:锁的“不可扩展性”真相

“PostgreSQL 在处理高并发写入场景时,其锁机制会显著拖累整体性能,甚至在特定负载下出现吞吐量下降。”该专家在演讲中展示的基准测试数据表明,当并发连接数超过 64 个时,Postgres 的锁竞争开始急剧恶化,事务延迟飙升,系统有效吞吐量趋于平缓甚至下降。这一现象被归因为“锁不可扩展”——即锁的冲突代价随并发数增长而非线性增加,最终成为系统瓶颈。

事实上,PostgreSQL 使用的是基于行级锁的多版本并发控制(MVCC)机制,配合共享锁与排他锁。在低并发场景下,这套体系表现得优雅且稳定;但在现代云计算环境中,动辄数百、数千个客户端同时访问数据库,锁管理器的争用开始显现短板。

深度剖析:锁在哪里“卡住”了?

根据多位内核贡献者的分析,问题主要集中在以下几个方面:

1. 锁管理器的单点争用
PostgreSQL 的锁管理器(Lock Manager)采用哈希表存储锁信息,所有后端进程在申请或释放锁时都需要通过一个全局互斥锁(LWLock)来保护该哈希表的并发访问。当并发连接数升高时,这个全局锁成为热点,所有进程都要排队等待,导致明显的上下文切换开销。

2. 锁升级与死锁检测机制
PostgreSQL 内置的死锁检测器定期扫描锁等待图,该扫描过程本身需要获取全局锁,进一步加剧了争用。此外,当大量事务同时请求同一数据页上的不同行锁时,行锁可能被迫升级为页锁或表锁,导致不必要的阻塞。

3. 长事务与空闲连接
在微服务架构中,连接池往往维持大量长连接。如果某些事务长时间持有锁不释放,会迫使后续请求等待时间增加,甚至触发级联等待链,造成全局性能雪崩。

影响几何?真实场景下的痛点

对于电商秒杀、金融交易、物联网数据采集等需要高并发写入的业务场景,Postgres 的锁扩展性问题已经不再是“理论风险”。一家头部互联网公司的数据库运维团队向媒体透露:“我们在双十一大促期间,核心订单库的 CPU 使用率并未打满,但吞吐量却早早触顶。最终定位发现,锁管理器内部的 spinlock 自旋消耗了超过 40% 的 CPU 时间。”

此外,云原生数据库领域中的多租户隔离(如 Amazon RDS for PostgreSQL、Aurora PostgreSQL)也受到此问题影响。多个租户共享同一数据库实例时,锁的全局争用会放大租户间的性能干扰。

业界回应:修补还是革新?

面对这一长期存在的挑战,PostgreSQL 社区并非毫无动作。在正在开发的 PostgreSQL 18 版本中,社区计划引入“细粒度锁分片”(Lock Sharding)技术,将全局锁管理器拆分为多个独立的锁域,以降低争用。同时,异步提交与乐观锁的混合使用也在实验中。

甲骨文公司数据库架构师评论称:“PostgreSQL 的优势在于其功能的完整性和稳定性,但锁机制的扩展性确实是其与 Oracle RAC、MySQL NDB Cluster 等方案相比的短板。”而另一面,Citus Data(现属微软)的工程师则建议:“对于明确的高并发场景,可以采用物理分片(sharding)或使用 Pgpool-II 等中间件做读写分离,从而减轻单一节点的锁压力。”

结语:锁的“不可扩展”或许是一种设计妥协

正如计算机科学中许多经典问题一样,“锁”本身就是并发控制的代价。PostgreSQL 选择在单节点上提供强一致性的事务隔离,就必然要承受锁争用的代价。随着硬件多核化与分布式数据库的普及,如何在不牺牲 ACID 的前提下重构锁管理器,将是决定 PostgreSQL 能否在新时代继续保持领先地位的关键。

对于开发者而言,理解锁的边界,合理设计数据模型与业务逻辑,或许比等待社区“修复”更为现实。毕竟,没有银弹——但每一次对锁的深入讨论,都在推动数据库技术向前迈进一步。

(本报记者 编译报道)