过去几个月,我一直被一个问题困扰。
一些独立开发者和创业公司创始人疯狂地拼凑技术栈,用 Redis 做缓存,RabbitMQ 做队列,Elasticsearch 做搜索,还有 MongoDB,为什么呢?
我也犯过同样的错误。当初开发 UserJot(我的反馈和路线图工具)时,我的第一反应是设计一个“规范”的架构,把所有功能都拆分成独立服务。后来我停下来问自己:如果直接用 PostgreSQL 来处理所有事情呢?
事实证明,大家一直对这个显而易见的问题避而不谈:
PostgreSQL 几乎可以做到这一切。
它的效果比你想象的还要好。
一、“PostgreSQL 无法扩展”的谬论正在让你损失金钱
你肯定听说过 PostgreSQL “只是个关系型数据库”,需要专门的工具来完成特定的任务。我以前也是这么想的,直到我发现 Instagram 仅用一个 PostgreSQL 实例就能支持 1400 万用户;Discord 可以处理数十亿条消息;Notion 整个产品都是基于 PostgreSQL 开发的。
但关键在于:他们使用 PostgreSQL 的方式已经和 2005 年不一样了。
二、排队系统
别再为 Redis 和 RabbitMQ 付费了。PostgreSQL 原生支持 LISTEN/NOTIFY,而且比大多数专用解决方案更能处理消息队列:
-- Simple job queue in pure Postgres
CREATE TABLE job_queue (
id SERIAL PRIMARY KEY,
job_type VARCHAR(50),
payload JSONB,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
processed_at TIMESTAMP
);
-- ACID-compliant job processing
BEGIN;
UPDATE job_queue
SET status = 'processing', processed_at = NOW()
WHERE id = (
SELECT id FROM job_queue
WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED
LIMIT 1
)
RETURNING *;
COMMIT;
这样就能实现精确一次处理,而且无需任何额外的基础设施。如果试着用 Redis 实现这一点,你会抓狂的。
在 UserJot 中,我正是使用这种模式来处理反馈提交、发送通知和更新路线图项目。只需一次事务,就能保证数据一致性,而且无需消息代理,也能降低复杂性。
三、键值存储
Redis 在大多数平台上最低每月收费 20 美元。PostgreSQL 的 JSONB 功能已包含在现有的数据库中,可以满足大部分需求:
-- Your Redis alternative
CREATE TABLE kv_store (
key VARCHAR(255) PRIMARY KEY,
value JSONB,
expires_at TIMESTAMP
);
-- GIN index for blazing fast JSON queries
CREATE INDEX idx_kv_value ON kv_store USING GIN (value);
-- Query nested JSON faster than most NoSQL databases
SELECT * FROM kv_store
WHERE value @> '{"user_id": 12345}';
该 @> 操作符是 PostgreSQL 的秘密武器。它比大多数 NoSQL 查询速度更快,而且能保持数据一致性。
四、全文检索
Elasticsearch 集群成本高昂且复杂,而 PostgreSQL 内置的全文搜索功能非常出色:
-- Add search to any table
ALTER TABLE posts ADD COLUMN search_vector tsvector;
-- Auto-update search index
CREATE OR REPLACE FUNCTION update_search_vector() RETURNS trigger AS $$
BEGIN
NEW.search_vector := to_tsvector('english', COALESCE(NEW.title, '') || ' ' || COALESCE(NEW.content, ''));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Ranked search results
SELECT title, ts_rank(search_vector, query) as rank
FROM posts, to_tsquery('startup & postgres') query
WHERE search_vector @@ query
ORDER BY rank DESC;
它开箱即用,支持模糊匹配、词干提取和相关性排序。
在 UserJot 的反馈搜索功能中,用户可立即通过标题、描述和评论中找到所需的功能请求,无需 Elasticsearch 集群,纯粹依靠 PostgreSQL 发挥其核心优势即可实现。
五、实时功能
抛开复杂的 WebSocket 架构,PostgreSQL 的 LISTEN/NOTIFY 机制可为你提供实时更新,无需任何额外服务:
-- Notify clients of changes
CREATE OR REPLACE FUNCTION notify_changes() RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('table_changes', json_build_object(
'table', TG_TABLE_NAME,
'action', TG_OP,
'data', row_to_json(NEW)
)::text);
RETURN NEW;
END;
LANGUAGE plpgsql;
你的应用程序会监听这些通知,并将更新推送给用户,不需要使用 Redis 发布或者订阅模式。
六、“专业化”工具的隐性成本
我们来算笔账,一个典型的“现代”堆栈的成本是:
- Redis:每月 20 美元
- 消息队列:每月 25 美元
- 搜索服务:每月 50 美元
- 3 项服务的监控费用:每月 30 美元
- 总计:每月 125 美元
但这只是主机托管费用,真正的痛点在于:
1、运营费用
- 三项不同的服务需监控、更新和调试
- 不同的扩展模式和故障模式
- 维护多种配置
- 独立的备份和灾难恢复程序
- 每项服务的安全考虑因素各不相同
2、开发复杂性
- 不同的客户端库和连接模式
- 协调跨多个服务的部署
- 系统间数据不一致
- 复杂的测试场景
- 不同的性能调优方法
如果你选择自建服务器,那么还需进行服务器管理、安全补丁,以及在 Redis 占用全部内存时不得不在凌晨 3 点进行调试。
但 PostgreSQL 通过单一服务即可处理所有这些事务,该服务本就在你的管理范围内。
七、可扩展的单一数据库
大多数人可能没有意识到:单个 PostgreSQL 实例就能处理海量数据。我们说的是每天数百万笔交易、数 TB 的数据以及数千个并发连接。
实际案例:
- Airbnb:单个 PostgreSQL 集群处理数百万笔预订
- Robinhood:数十亿笔金融交易
- GitLab:基于 PostgreSQL 的完整 DevOps 平台
PostgreSQL 的魅力在于其架构,它具备极强的垂直扩展能力,而当你最终需要水平扩展时,也有很多成熟的方案可选择,例如:
- 读取副本以进行查询扩展
- 分区处理大型表
- 连接池实现并发
- 分布式架构的逻辑复制
大多数企业永远不会遇到这些限制。除非你需要处理数百万用户或复杂的分析工作负载,否则单个实例可能就足够了。
相比之下,管理那些扩展能力不一的独立服务则截然不同:你的 Redis 可能内存已达上限,消息队列可能吞吐量不足,而搜索服务则需要完全不同的硬件配置。
八、从一开始就停止过度设计
现代开发的最大陷阱,莫过于架构空想。我们总在为尚未出现的问题设计系统,针对从未遇到的流量做方案,为可能永远达不到的规模做准备。
1、过度设计循环
- “我们或许有一天需要扩大规模”;
- 添加 Redis、队列、微服务和多个数据库;
- 花费数月时间调试集成问题;
- 面向 47 位用户发布;
- 每月支付 200 美元购买的基础设施,其实只需一台 5 美元的 VPS 就能运行;
与此同时,你的竞争对手交付速度更快。因为他们不会在真正需要分布式系统之前,就盲目投入精力去搭建和维护它。
2、更好的方法
- 从 PostgreSQL 开始,简单起步;
- 监控实际存在的瓶颈,而不是臆想出来的瓶颈;
- 当达到实际限制时,调整特定组件的规模;
- 仅在方案能解决实际问题时,才引入复杂设计。
你的用户并不关心你的架构,他们只关心你的产品是否好用,能否解决他们的问题。
九、当你真正需要专用工具时
专用工具自有其用处,但可能只有出现以下情况才用到它们:
- 每分钟处理超过 10 万个作业;
- 需要亚毫秒级的缓存响应;
- 正在对 TB 级的数据进行复杂的分析;
- 拥有数百万并发用户;
- 需要满足特定一致性要求的全球数据分发。
十、为什么这真的很重要
最让我震惊的是:PostgreSQL 可以同时作为主数据库、缓存、队列、搜索引擎和实时系统,而且还能在所有组件间保持 ACID 事务。
-- One transaction, multiple operations
BEGIN;
INSERT INTO users (email) VALUES ('user@example.com');
INSERT INTO job_queue (job_type, payload) VALUES ('send_welcome_email', '{"user_id": 123}');
UPDATE kv_store SET value = '{"last_signup": "2024-01-15"}' WHERE key = 'stats';
COMMIT;
试试在 Redis、RabbitMQ 和 Elasticsearch 之间执行这样的操作,看你能不能不崩溃。
十一、无聊的技术却能获胜
PostgreSQL 并不引人注目,它既没有花里胡哨的官网,也没有像 TikTok 那样爆红的平台。但数十年来,当其他数据库不断迭代更替时,它始终在背后默默支撑着互联网的运转。
选择这类朴实可靠、能稳定落地的技术,本身就很有讲究。
十二、下一个项目的行动步骤
- 先只使用 PostgreSQL 开始:不要急于添加其他数据库;
- 使用 JSONB 实现灵活性:既能享受无模式的优势,又能拥有 SQL 的强大功能;
- 在 PostgreSQL 中实现队列:节省成本并降低复杂性;
- 真正遇到瓶颈时才添加专用工具:注意,不是想象中的瓶颈。
十三、我的真实经历
UserJot 的开发正是对这一理念的完美检验。作为一款反馈与路线图工具,它需要:
- 提交反馈后实时更新;
- 对数千个功能请求进行全文搜索;
- 用于发送通知的后台任务;
- 为频繁访问的路线图提供缓存;
- 存储用户偏好和设置的键值存储。
我的整个后端仅由单个 PostgreSQL 数据库构成。没有 Redis,没有 Elasticsearch,也没有消息队列。从用户身份验证到实时 WebSocket 通知,一切都由 PostgreSQL 处理。
结果如何?我可以更快地发布功能,需要调试的组件更少,基础设施成本也降到了最低。所有底层工作都由 PostgreSQL 完成:用户提交反馈、搜索功能或获取路线图变更的实时更新。
这早已不是纸上谈兵,而是承载着真实用户与业务数据,稳定运行于生产和环境。
十四、令人不安的结论
PostgreSQL 或许过于优秀反而成了负担。它功能如此强大,以至于让其他数据库在 90% 的应用场景中显得多余。行业惯例让我们相信每件事都需要专用工具,但或许我们只是把事情搞得比实际更复杂。
初创公司不需要成为分布式系统的展示平台,它需要解决真实用户面临的实际问题。PostgreSQL 让你能够专注于此,而不是一直在维护基础设施。
所以下次如果有人提议添加 Redis “提升性能”或添加 MongoDB “增强灵活性”时,不妨反问:“你是否尝试过先用 PostgreSQL 实现?”
答案或许会让你惊讶。当我将 UserJot 完全构建在 PostgreSQL 之上时也感到非常意外,而它至今运行得无比顺畅。
希望这篇文章能为你提供一个不同的技术选型视角。如果你对类似的技术深度探讨感兴趣,欢迎在 云栈社区 查看更多相关内容。