一条不到 8000 字节的 Postgres 通知,能不能扛起原本交给消息中间件的工作?
DBOS 给出的回答比行业惯例乐观:LISTEN/NOTIFY 在合适的负载和架构下可以扩展,不该因为它内置在数据库里,就先判定“只能做小玩具”。这个方向有价值。很多团队确实不是缺 Kafka,而是被告知“做异步就该上 Kafka”。
麻烦也很具体:本次可核验材料没有给出完整测试数字。页面显示的发布日期还是 2026 年 7 月 24 日,目前无法确认是预排时间、元数据错误,还是尚未正式发布。因此,这更适合被视作一项待复核的技术主张,而非已经坐实的性能新闻。
DBOS 的结论成立到哪一步,目前还缺数据
DBOS 想推翻的行业印象很明确:LISTEN/NOTIFY 连接多了会崩,吞吐高了会堵,只适合开发环境或低频通知。
但标题里的 “actually scales” 必须由边界条件支撑。现有材料没有提供下面这些可核验信息:
| 基准项目 | 当前可核验状态 | 为什么必须公开 |
|---|---|---|
| 并发监听连接数 | 未提供 | LISTEN 依赖会话连接,连接规模直接影响资源占用 |
| 每秒通知吞吐 | 未提供 | 没有吞吐,就无法回答“能扛多少” |
| p50、p95、p99 延迟 | 未提供 | 平均延迟会掩盖队列堆积和慢监听者 |
| PostgreSQL 版本 | 未提供 | 不同版本的实现和性能表现不能混为一谈 |
| CPU、内存、存储配置 | 未提供 | 单机硬件可能决定大部分成绩 |
| 负载拓扑 | 未提供 | 单库单区与多租户、跨地域完全是两类问题 |
| 故障与恢复测试 | 未提供 | 正常运行快,不代表断线和主库切换后可靠 |
所以,目前能接受的是一个有限结论:LISTEN/NOTIFY 的性能上限可能高于许多人的经验判断。至于它在多少连接、多少通知、什么尾延迟下仍然稳定,材料不足,不能替 DBOS 补数字。
这也暴露了很多基础设施基准测试的老问题。顺风跑分容易,逆风测试才值钱。监听者长期占着事务、连接突然断开、主库切换、通知队列接近上限,这些场景比峰值吞吐更接近生产环境。
它能跑得快,因为它承担的事情本来就少
LISTEN/NOTIFY 很轻,原因并不神秘。它没有替应用完成持久化日志、消息重放、消费组协调和偏移量管理。
按照 PostgreSQL 官方文档,它有几条容易被性能标题遮住的规则:
NOTIFY在事务提交后才对外生效。事务回滚,通知也不会发出。- 监听会话如果正处于事务中,通知要等事务结束后才能交付。
- 默认配置下,通知载荷必须短于 8000 字节。
- 通知发给当前正在监听对应频道的会话.监听者断线期间没有历史消息可补。
- 标准构建中的通知队列容量约为 8GB,但这不等于 8GB 的持久化消息日志。
- 监听会话长时间不结束事务,可能阻止队列清理。队列满后,发送
NOTIFY的事务可能无法提交。 LISTEN是会话级状态.使用 PgBouncer 一类事务级连接池时,通常要为监听器保留专用长连接。
最后一点很容易在架构图里消失。应用查询可以随便借连接,监听器不行。它必须知道自己连着哪一个后端会话,也要处理断线、重连和重新执行 LISTEN。
更稳妥的做法,是让通知只携带一个短标识,例如任务 ID、订单 ID 或 outbox 记录 ID。真实状态继续放在数据库里。
典型流程很朴素:
- 业务事务更新数据同时写入 outbox 表。
- 事务内发送一个只含记录 ID 的
NOTIFY。 - 监听器收到信号再回数据库读取并处理记录。
- 如果通知因断线丢失定时扫描 outbox 补偿。
这样一来,可靠性来自业务表和补偿扫描,NOTIFY 只负责减少轮询延迟。通知丢了,任务仍在;重复通知,也能按数据库状态做幂等处理。
这套设计确实实用。但要认清收益来源:LISTEN/NOTIFY 没有忽然变成消息队列,是数据库本身承担了事实来源、持久化和恢复责任。
省掉 Kafka 可以,先把交付语义列清楚
“要不要引入消息系统”经常被问成性能问题。其实多数时候,决策取决于交付语义和组织成本。
| 能力 | LISTEN/NOTIFY | Redis Pub/Sub | Redis Streams | Kafka |
|---|---|---|---|---|
| 断线后重放 | 不支持 | 不支持 | 支持 | 支持 |
| 持久化业务日志 | 不提供 | 不提供 | 提供流记录 | 提供分区日志 |
| 消费组 | 不支持 | 不支持 | 支持 | 支持 |
| 消费进度管理 | 不支持 | 不支持 | 支持 | 支持 |
| 慢消费者治理 | 能力有限 | 能力有限 | 可观察积压 | 以 lag 和保留策略治理 |
| 跨系统解耦 | 较弱,绑定 Postgres | 中等 | 中等 | 强 |
| 新增运维组件 | 无 | 有 | 有 | 有 |
| 合适角色 | 状态变化信号 | 实时广播 | 中等规模任务流 | 可重放事件流、数据管道 |
这里不能把 Redis 和 Kafka统称为“独立消息系统”后就一笔带过。Redis Pub/Sub 同样不提供离线重放,语义上反而更接近 LISTEN/NOTIFY;Redis Streams 和 Kafka 才补上了持久记录、消费进度等能力。Kafka 又进一步强化了分区扩展、长时间保留和跨系统数据流。
已使用 Postgres、负载中等、事件只在同一业务系统内流转的团队,完全可以认真评估 LISTEN/NOTIFY。典型场景包括缓存失效、界面刷新、后台任务唤醒、配置变更提醒,以及“数据库里已经有可靠任务记录,只差一个低延迟信号”。
以下场景不该只靠它:
- 订单、支付、账务事件要求一条不丢,还要事后审计。
- 新消费者上线后需要重放历史。
- 多组消费者要独立维护处理进度。
- 生产者和消费者分属不同系统、团队或地域。
- 消费速度波动很大,需要明确的背压和积压治理。
- 主库故障切换期间也必须保持可验证的交付连续性。
Postgres 应用架构师接下来该做的,不是争论它算不算“真正的消息队列”,而是把生产拓扑原样搬进压测:专用监听连接、真实事务长度、连接池模式、慢消费者、重连、主库切换、队列占用和 p99 延迟,一个都别删。
正在评估 Kafka、Redis Streams 或云消息服务的技术负责人,可以先问两个问题:业务是否需要重放?通知丢失后,数据库扫描能否完整恢复?两个答案分别是“不需要”和“可以”,采购独立消息系统就有理由延后。
技术史里常有“合久必分,分久必合”。早年的应用把状态、任务和通知塞进一个数据库;微服务时代又把缓存、队列、日志拆成一排基础设施。如今团队重新审视 LISTEN/NOTIFY,不是历史倒车,而是在偿还过度拆分带来的运维成本。
DBOS 这次点中了一个真实痛点:少一套集群,就少一套监控、升级、权限、故障演练和夜间告警。只是它还需要公开完整的测试脚本、Postgres 版本、硬件、连接数、吞吐、尾延迟,以及断线和故障恢复结果。
跑分证明“能跑”只是开场。生产系统最终结算的,是丢一次通知之后还能不能把账找回来。
