Postgres 的 LISTEN/NOTIFY 机制到底能不能扩展?这个问题在开发者社区里争议不小。很多人觉得它因为全局锁的存在,性能注定拉胯,没法在高并发场景下担当重任。但 DBOS 团队最近用实际行动打了脸——他们在单台 Postgres 服务器上跑出了每秒 6 万次写入,延迟还控制在毫秒级。相比之下,那些传统的轮询方案要么延迟高得离谱,要么把数据库负载推上天。对于 LLM 响应流这类既要低延迟又要持久化通知的场景,LISTEN/NOTIFY 提供了一个更干净的发布/订阅解决方案。
核心要点
- 固有偏见该打破了:LISTEN/NOTIFY 因为全局锁被贴上“不可扩展”的标签,但实测证明,优化之后完全能打。
- 性能数据很硬:单台 Postgres 服务器实现每秒 60,000 次写入,延迟毫秒级。
- 轮询输在哪:轮询方案要么延迟高,要么让数据库累死;LISTEN/NOTIFY 让读取者在数据到达时瞬间唤醒,两全其美。
- 关键场景浮现:特别适合需要低延迟、持久化通知的流式处理,比如大语言模型逐字输出的响应流。
详细分析
挑战与误区:全局锁的性能瓶颈
Postgres 的 LISTEN/NOTIFY 在开发者圈子里口碑一直很微妙,根本原因在于它内部用了全局锁,导致一些非直观的、文档里也没写清楚的性能特性。很多人下意识觉得,高并发写入时全局锁就是死xue。但 DBOS 的研究点破了关键:“非直观的行为”不等于“不可扩展”。只要摸透底层机制,做有针对性的优化,这套机制完全可以成为高性能实时系统的地基。
架构优化:实现低延迟流处理
如果要基于 Postgres 搭一个流处理系统,常规做法是建一个流表,把每个数据块(比如 LLM 吐出来的一个 Token)作为新行插入。问题来了:读取端怎么高效地知道有新数据来了?传统轮询方案陷入两难——轮询间隔太长,延迟就上去了,交互体验变差;轮询间隔太短,大量并发请求瞬间把数据库搞垮。LISTEN/NOTIFY 的解法很优雅:读取者直接进入阻塞状态,等通知。写入者一发布新数据块,读取者立刻被唤醒。这样既不浪费资源,又能做到极低的响应延迟。
行业影响
这个发现对实时数据驱动的应用意义不小。生成式 AI 普及之后,LLM 的流式输出几乎成了标配。DBOS 的优化方案证明了一件事:开发者完全可以留在成熟的 Postgres 生态里,用原生的 LISTEN/NOTIFY 实现过去需要专门消息中间件才能达到的性能。系统架构更简单了,通知和数据库事务之间的一致性、持久性也有保障,运维复杂度自然就降下来了。
常见问题
问题 1:为什么 LISTEN/NOTIFY 以前被认为难以扩展?
直接原因就是它处理通知时用了全局锁,在某些高并发配置下会引发严重的资源竞争。再加上性能表现有点反直觉,官方文档又没有给出大规模场景下的优化指南,大家自然就望而却步了。
问题 2:相比于轮询(Polling),LISTEN/NOTIFY 的核心优势是什么?
轮询本质上是拿延迟和数据库负载做交易——想要低延迟就得高频查询,高频查询就会压垮数据库;想要数据库喘口气就得拉长轮询间隔,延迟又上去了。LISTEN/NOTIFY 走的是事件驱动路线,读取者只在有数据时才被唤醒,毫秒级延迟和数据库压力之间不再需要二选一。
