大家好,我是MAI麦造
最近又把之前做到一半的一个小网站维护了起来
之前停下的原因是因为这本来只是一个很小的功能,
但我需要分别写前后端 ,
然后用 redis 做缓存、mongo 做存储、mysql 做后端存储、Elasticsearch 做全文索引的时候...
我是有点蚌埠住了。
不过最近我找到了一个优雅的解决方案:postgres
!!!
本文部分内容翻译自:Postgres is Too Good (And Why That's Actually a Problem)。 结尾点击阅读原文跳转。
Postgres 能搞定所有这些事
在固有的认知中,一直认为 Postgres "只是一个关系型数据库"。
必须为消息队列、全文检索使用"专业的工具"
但如果你知道:
-
Instagram 在单个 Postgres 实例上扩展到 1400 万用户
-
Discord 处理着数十亿的消息
-
Notion 整个产品都是基于 Postgres 构建的。
这个点的关键在于:他们不再像 2005 年那样使用 Postgres 了。
"专业工具"的隐藏成本
一个典型的"现代"技术栈成本如下:
-
Redis:每月 20 美元
-
消息队列(Kafka/RebbitMQ):每月 25 美元
-
搜索服务(Elasticsearch):每月 50 美元
-
监控 3 个服务:每月 30 美元
-
总计:$125/月
但这只是托管费用, 真正痛苦是,
维护成本:
-
三个不同的服务用于监控、更新和调试
-
不同的扩展模式和故障模式
-
同时更新多种配置
-
分离备份和灾难恢复流程
-
每个服务都有不同的安全考虑因素
开发复杂性:
-
不同的客户端库和连接模式
-
处理多个服务之间的部署
-
系统之间数据不一致
-
复杂的测试场景
-
不同的性能调优方法
如果选择自行托管,还需加上服务器管理、安全补丁,以及当 Redis 爆内存时,凌晨 3 点的维护...
而现在,你可以通过管理Postgres服务来处理所有这些!
这听起来有点疯狂,但接下来我将告诉你具体怎么实现:
队列系统
停止额外为 Redis 和 RabbitMQ 的云服务付费。
Postgres 原生支持 LISTEN / NOTIFY
,并且处理任务队列比大多数专用解决方案更出色:
python
-- 简单的队列示例
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 任务处理
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;
这个符合 ACID 标准的任务状态更新功能,
要是用 Redis 去搞,看看要掉多少头发?😏
我用这个方法处理反馈提交、发通知、更新路线图,
一个事务搞定,保证数据一致,不用操心消息代理那些破事儿。
Key-Value 键值存储
Redis 在大多数平台上最低也要 $20/月。
Postgres 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}';
这个 @>
操作符是 Postgres 的秘密武器!
比大多数 NoSQL 查询都快,而且数据也稳。
全文搜索
受不了 Elasticsearch 集群的又贵又复杂,那一定要试试Postgres 自带的全文搜索:
sql
-- 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;
直接就能搞定模糊匹配 、词干提取 和相关性排序,简直不要太方便。
对于搜索,用户能瞬间在标题、描述和评论里找到所需。
根本不用 Elasticsearch 集群,纯粹靠 Postgres 就能发挥它最拿手的功能。
实时功能
还有那些复杂的 WebSocket 基础设施,也可以抛一边。
Postgres LISTEN / NOTIFY
直接给你实时更新,零额外服务:
sql
-- 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 的 pub/sub
ACID 事务
让我震撼的是:Postgres 强到能同时当你的主数据库、缓存、队列、搜索引擎,还搞实时系统。
最牛的是,啥都能保持 ACID 事务!
sql
-- 一个事务,多个操作
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 上搞这些操作,不哭都难。
可扩容的单个数据库
大部分人都不知道:单个 Postgres 实例真能扛住大场面。我指的是每天几百万笔交易,TB 级别的数据量,还有成千上万并发连接。
真实的案例
-
Airbnb:单个 Postgres 集群搞定上百万次预订
-
Robinhood:处理了数十亿笔金融交易
-
GitLab:整个 DevOps 平台都基于 Postgres
而真正厉害的地方是Postgres的架构。
它的垂直拓展做的很棒,但当你需要水平拓展的时候,也有这样成熟的方案可选:
-
Read replicas 只读副本 用来拓展查询
-
Partitioning 大表分区
-
并发连接池
-
分布式环境下的逻辑复制
大多数企业根本达不到这些限制。
你可以一直用单个实例,直到你要处理上百万用户或者复杂的分析工作负载,再考虑拓展架构。
从一开始就别瞎折腾了
现在开发里最大的坑就是搞那些花里胡哨的架构。
设计的系统,
要么是为了解决根本没出现过的难题,
要么是按着从未见过的流量去设计,
要么是想着可能永远也达不到的规模。
过度设计的死亡循环:
-
"咱们总有一天得扩规模呢!"
-
"快加上 Redis、队列、微服务、多个数据库试试!"
-
花几个月时间调试集成问题
-
上线后只有 47 个用户
-
凉凉...
每月花 200 美元买的基础设施,其实 5 美元的 VPS 就能搞定!
更好的方法是:
-
用 Postgres 从简单开始试试!
-
盯着真瓶颈,别瞎折腾那些假的!
-
碰到真·瓶颈了,就针对性地给某些部件加码!
-
只在你真的需要解决实际问题的时候才增加复杂性
要知道,你的用户根本不在乎你的架构。
他们关心的是你的产品能不能用,能不能解决他们的问题。
"我"的真实使用体验
我整个后端就一个 Postgres 数据库。
没 Redis,没 Elasticsearch,没消息队列。
就靠 Postgres 从用户认证到实时 WebSocket 通知全搞定!
它给我的系统提供了:
-
实时更新用户提交的反馈
-
数千个功能中的全文搜索
-
后台任务用于发送通知
-
缓存经常访问的路线图
-
用键值对存储用户偏好和设置
结果呢?我发布新功能更快了,调试的环节也少了,基础设施成本几乎可以忽略不计。用户提交反馈、搜索功能或者获取路线图更新的实时信息------背后全都是 Postgres 在默默支撑着
这不是空谈了,是实际生产环境中的真实用户和真实数据。
什么时候 Postgres 不够用了?
当然,这不是说那些工具没用!
但当你真的需要的时候,这时你的系统可能是:
-
每分钟处理超过 10 万个任务啊!
-
得要亚毫秒级别的缓存响应速度
-
你正在对 TB 级别的海量数据做复杂分析
-
你们同时有成千上万用户呢!
-
你这得全球数据分布还得有特定一致性要求啊