一台PostgreSQL能替Kafka、替Redis、替MongoDB、替ClickHouse,甚至替掉图数据库和微服务——这是科技博主Raphael Bauer今年2月那篇长文的核心主张。他从2003年做ColumbaDB研究项目开始用PostgreSQL,一路用到最近给自家产品Privatracker处理高并发时序数据,靠的是TimescaleDB插件。PostgreSQL首个版本发布于1996年,将近三十年积累下来的功能确实惊人。
但开发者社区讨论这个话题时,早就不把它当一句口号,而是拆成了三档:默认优先用PostgreSQL(社区普遍支持)、无论如何都往里塞(开始有争议)、单个实例扛下所有负载(争议最大)。Bauer这篇文章列的清单——全文搜索、JSON存储、消息队列、时序数据、向量库、缓存,全部塞进同一个PostgreSQL——恰好落在最后两档,也正是被质疑最集中的地方。
少装系统的诱惑,和它藏起来的账
过去十年,团队被Kafka、Elasticsearch、Redis这类专用系统的运维成本折腾得够够的:数据同步、多套监控、各种故障模式互相打架。PostgreSQL插件生态这几年确实猛,pgvector、TimescaleDB、JSONB索引一个接一个补齐能力短板,Timescale、Supabase、Neon这些云厂商也在拼命推"一个数据库搞定一切"的叙事——毕竟这套故事对它们的商业模式也有利。
Bauer的文章是这套叙事最典型的样本:全是正面案例,Contentful用它做全文搜索、《卫报》从MongoDB切换过来、社区里有人用它实现队列。但整篇文章找不到一处"什么时候会撑不住"。
模拟出来的队列和缓存,少了什么
PostgreSQL的核心复制机制是单主模型,standby能分担读、能做故障转移,但写入始终要经过primary。同步复制虽然更安全,却也会拉长提交延迟、加重锁竞争——这不是配置问题,是架构本身的限制。
MVCC是PostgreSQL处理并发的方式,更新和删除后留下的旧行版本要靠autovacuum慢慢回收。普通业务表还好,但队列表、缓存表、高频计数器这类负载,行变更的频率远超普通场景,容易把表和索引撑大,拖慢整个数据库——不只是拖慢这一张表。
用SELECT ... FOR UPDATE SKIP LOCKED模拟队列是社区常见做法,PostgreSQL官方文档也承认它能有效避免消费者间的锁竞争。但这个机制设计初衷是通用查询优化,不是消息队列的死信重试、消费者组这些语义,模拟到复杂业务场景时,很容易变成自己在数据库里重新写了一个更简陋的消息中间件。
- 风险.
UNLOGGED表常被用来模拟Redis缓存,但它并非崩溃安全——数据库崩溃后可能被清空,也不会同步到standby,故障恢复后你面对的可能是一个空缓存。
什么信号该触发拆分,而不是继续信一个系统
只读副本靠回放primary的WAL日志追数据,长时间分析查询一旦跟vacuum清理或DDL冲突,PostgreSQL要么直接取消这条standby查询,要么延迟WAL回放,复制延迟就这么涨起来的。这意味着"读写分离"并不等于真正的分析隔离,副本依然要看primary的脾气。
连接数也是共享资源。max_connections调大不是免费操作,背后跟着内存和进程管理的连锁反应;队列、缓存、业务查询挤在同一个连接池里,谁先扛不住是运气问题。更麻烦的是Reddit和Hacker News上反复出现的经验:一张"简单的队列表"会慢慢长出join、业务状态、重试逻辑,业务逻辑和存储过程深度绑进数据库后,想再拆出去,迁移成本和风险都比当初想象的高得多。
Postgres-first值得信,Postgres-only该问一句"为什么不拆"。
社区给出的判断信号很具体:autovacuum开始跟不上表膨胀速度、复制延迟主要由队列或缓存这类次要负载引起、单一查询开始明显拖累其他业务——这些出现任何一条,就是该把负载挪出去的时候,而不是继续相信"一个系统能扛住一切"。
- 结论.把PostgreSQL当默认选项没问题,但别把"不拆分"本身当成目标,观察指标比信念更可靠。
正在做技术选型的团队,比起被一篇个人经验贴说服去"少装系统",更该先问自己:现在这点负载,离触发信号还有多远。云托管的PostgreSQL能缓解一部分运维负担,但缓解不了单主写入和MVCC膨胀这些物理层限制——这些账迟早要自己算清楚。
