注册

Postgres 杀疯了,堪称 “六边形战士”,还要 Redis 干啥?

我们需要谈谈困扰我几个月的事情。我一直看到独立黑客和初创公司创始人疯狂地拼凑各种技术栈,用 Redis 做缓存,用 RabbitMQ 做队列,用 Elasticsearch 做搜索,还有用 MongoDB……为什么?


我也犯过这种错误。当我开始构建UserJot(我的反馈和路线图工具)时,我的第一反应是规划一个“合适的”架构,为所有功能提供独立的服务。然后我停下来问自己:如果我把所有功能都用 Postgres 来做会怎么样?


事实证明,房间里有一头大象,但没人愿意承认:



而且它的效果比你想象的还要好。


“Postgres 无法扩展”的谬论正在让你损失金钱?


让我猜猜——有人告诉你,Postgres“只是一个关系数据库”,需要专门的工具来完成专门的工作。我以前也是这么想的,直到我发现 Instagram 可以在单个 Postgres 实例上扩展到 1400 万用户。Discord 处理数十亿条消息。Notion 的整个产品都是基于 Postgres 构建的。


但问题是:他们不再像 2005 年那样使用 Postgres。


队列系统


别再为 Redis 和 RabbitMQ 付费了。Postgres 原生支持LISTEN/NOTIFY并且比大多数专用解决方案更好地处理作业队列:


-- Simple job queue in pure Postgres
CREATETABLE job_queue (
    id SERIAL PRIMARY KEY,
    job_type VARCHAR(50),
    payload JSONB,
    status VARCHAR(20DEFAULT'pending',
    created_at TIMESTAMPDEFAULT 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'
    ORDERBY created_at
    FORUPDATESKIP LOCKED
    LIMIT 1
)
RETURNING *;
COMMIT;

这让你无需任何额外的基础设施就能实现 Exactly-Once 的处理。不妨试试用 Redis 来实现,会让你很抓狂。


在 UserJot 中,我正是使用这种模式来处理反馈提交、发送通知和更新路线图项目。只需一次事务,即可保证一致性,无需消息代理的复杂性。


键值存储


Redis 在大多数平台上的最低价格为 20 美元/月。Postgres JSONB 已包含在您现有的数据库中,可以满足您的大部分需求:


-- Your Redis alternative
CREATETABLE kv_store (
    key VARCHAR(255PRIMARY 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
WHEREvalue @>'{"user_id": 12345}';

运算符@>是 Postgres 的秘密武器。它比大多数 NoSQL 查询更快,并且数据保持一致。


全文搜索


Elasticsearch 集群价格昂贵且复杂。Postgres 内置的全文搜索功能非常出色:


-- Add search to any table
ALTERTABLE posts ADDCOLUMN search_vector tsvector;

-- Auto-update search index
CREATEOR REPLACE FUNCTION update_search_vector()
RETURNStriggerAS $
BEGIN
    NEW.search_vector := to_tsvector('english',
        COALESCE(NEW.title, ''||' '||
        COALESCE(NEW.content, '')
    );
    RETURNNEW;
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
ORDERBY rank DESC;

这可以处理模糊匹配、词干提取和相关性排名。


对于 UserJot 的反馈搜索,此功能可让用户跨标题、描述和评论即时查找功能请求。无需 Elasticsearch 集群 - 只需使用 Postgres 即可发挥其优势。


实时功能


忘掉复杂的 WebSocket 基础架构吧。Postgres LISTEN/NOTIFY无需任何附加服务即可为您提供实时更新:


-- Notify clients of changes
CREATEOR REPLACE FUNCTION notify_changes()
RETURNStriggerAS $
BEGIN
    PERFORM pg_notify('table_changes',
        json_build_object(
            'table', TG_TABLE_NAME,
            'action', TG_OP,
            'data', row_to_json(NEW)
        )::text
    );
    RETURNNEW;
END;
LANGUAGE plpgsql;

您的应用程序会监听这些通知并向用户推送更新。无需 Redis 的发布/订阅机制。


“专业”工具的隐性成本


我们来算一下。一个典型的“现代”堆栈的成本是:



  • Redis:20美元/月
  • 消息队列:25美元/月
  • 搜索服务:50美元/月
  • 监控 3 项服务:30 美元/月
  • 总计:每月 125 美元

但这还只是托管成本。真正的痛点在于:


运营开销:



  • 三种不同的服务用于监控、更新和调试
  • 不同的缩放模式和故障模式
  • 需要维护多种配置
  • 单独的备份和灾难恢复程序
  • 每项服务的安全考虑因素不同

开发复杂性:



  • 客户端库和连接模式
  • 多个服务的部署
  • 间数据不一致
  • 的测试场景
  • 的性能调优方法

如果您自行托管,请添加服务器管理、安全补丁以及当 Redis 决定消耗所有内存时不可避免的凌晨 3 点调试会话。


Postgres 使用您已经管理的单一服务来处理所有这些。


扩展的单一数据库


大多数人可能没有意识到:单个 Postgres 实例就能处理海量数据。我们指的是每天数百万笔交易、数 TB 的数据以及数千个并发连接。


真实世界的例子:



  • Airbnb:单个 Postgres 集群处理数百万个预订
  • Robinhood:数十亿笔金融交易
  • GitLab:Postgres 上的整个 DevOps 平台

Postgres 的架构魅力非凡。它被设计成具备极佳的垂直扩展能力,而当你最终需要水平扩展时,它也有以下成熟的方案可供选择:



  • 用于查询扩展的读取副本
  • 大表分区
  • 并发连接池
  • 分布式设置的逻辑复制

大多数企业从未达到过这些限制。在处理数百万用户或复杂的分析工作负载之前,单个实例可能就足够了。


将此与管理所有以不同方式扩展的单独服务进行比较 - 您的 Redis 可能会耗尽内存,而您的消息队列则会遇到吞吐量问题,并且您的搜索服务需要完全不同的硬件。


从第一天起就停止过度设计


现代开发中最大的陷阱是架构式的“宇航员”。我们设计系统时,面对的是我们从未遇到过的问题,我们面对的是从未见过的流量,我们可能永远无法达到的规模。


过度设计循环:



  1. “我们可能有一天需要扩大规模”
  2. 添加 Redis、队列、微服务、多个数据库
  3. 花费数月时间调试集成问题
  4. 向 47 位用户推出
  5. 每月支付 200 美元购买可在 5 美元 VPS 上运行的基础设施

与此同时,您的竞争对手的发货速度更快,因为他们在需要分布式系统之前并没有管理它。


更好的方法:



  • 从 Postgres 开始
  • 监控实际的瓶颈,而不是想象的瓶颈
  • 当达到实际极限时扩展特定组件
  • 仅在解决实际问题时才增加复杂性

你的用户并不关心你的架构。他们关心的是你的产品是否有效,是否能解决他们的问题。


当你真正需要专用工具时


别误会我的意思——专用工具自有其用处。但你可能在以下情况之前不需要它们:



  • 您每分钟处理 100,000 多个作业
  • 您需要亚毫秒级的缓存响应
  • 您正在对数 TB 的数据进行复杂的分析
  • 您有数百万并发用户
  • 您需要具有特定一致性要求的全局数据分布

如果您在公众号上阅读强哥这篇文章,那么您可能还没有到达那一步。


为什么这真的很重要


让我大吃一惊的是:Postgres 可以同时充当您的主数据库、缓存、队列、搜索引擎和实时系统。同时还能在所有方面保持 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 上执行此操作,不要哭泣。


无聊的技术却能获胜


Postgres 并不引人注目。它没有华丽的网站,也没有在 TikTok 上爆红。但几十年来,在其他数据库兴衰更迭之际,它一直默默地支撑着互联网。


选择简单、可靠且有效的技术是有道理的。


下一个项目的行动步骤



  1. 仅从 Postgres 开始- 抵制添加其他数据库的冲动
  2. 使用 JSONB 实现灵活性- 借助 SQL 的强大功能,您可以获得无架构的优势
  3. 在 Postgres 中实现队列——节省资金和复杂性
  4. 仅当达到实际极限时才添加专用工具- 而不是想象中的极限

我的真实经历


UserJot 的构建是这一理念的完美测试案例。它是一个反馈和路线图工具,需要:



  • 提交反馈时实时更新
  • 针对数千个功能请求进行全文搜索
  • 发送通知的后台作业
  • 缓存经常访问的路线图
  • 用于用户偏好和设置的键值存储

我的整个后端只有一个 Postgres 数据库。没有 Redis,没有 Elasticsearch,没有消息队列。从用户身份验证到实时 WebSocket 通知,一切都由 Postgres 处理。


结果如何?我的功能交付速度更快,需要调试的部件更少,而且基础设施成本也降到了最低。当用户提交反馈、搜索功能或获取路线图变更的实时更新时,一切都由 Postgres 完成。


这不再只是理论上的。它正在实际生产中,通过真实的用户和真实的数据发挥作用。


令人不安的结论


Postgres 或许好得过头了。它功能强大,以至于大多数其他数据库对于 90% 的应用程序来说都显得多余。业界一直说服我们,所有事情都需要专门的工具,但或许我们只是把事情弄得比实际需要的更难。


你的初创公司不必成为分布式系统的样板。它需要为真正的人解决真正的问题。Postgres 让你专注于此,而不是照看基础设施。


因此,下次有人建议添加 Redis 来“提高性能”或添加 MongoDB 来“提高灵活性”时,请问他们:“您是否真的先尝试过在 Postgres 中执行此操作?”


答案可能会让你大吃一惊。我知道,当我完全在 Postgres 上构建UserJot时,它就一直运行顺畅。



作者:强哥叨逼叨
来源:juejin.cn/post/7517200182725296178

0 个评论

要回复文章请先登录注册