在过去的几个月中,有一个现象一直萦绕在我心头,令我深感困扰:我目睹了太多独立开发者和初创公司创始人在技术选型时,不假思索地堆砌各种专用工具——用Redis作缓存,用RabbitMQ处理消息队列,用Elasticsearch实现搜索,甚至引入MongoDB等非关系型数据库。这究竟是为了什么?

坦白说,我也曾陷入同样的思维定式。当我开始构思UserJot——一个用户反馈与产品路线图管理工具时,我的第一反应同样是规划一个“标准”的分布式架构,为每个功能模块配备独立的技术组件。但就在那一刻,我停下来问了自己一个关键问题:如果我只用PostgreSQL来实现所有功能,会怎样?

这个问题的答案,揭示了一个许多人刻意回避的事实:

PostgreSQL几乎能满足你的所有需求,而且它的表现远超你的想象。

🔍 关于“PostgreSQL无法扩展”的迷思

你是否也曾被这样的观点影响:PostgreSQL“仅仅是个关系型数据库”,而专业的工作必须交给专业的工具?我曾经也深信不疑,直到我发现:

  • Instagram在单个PostgreSQL实例上支撑了1400万用户

  • Discord处理着数十亿条消息的庞大规模

  • Notion的整个产品体系都构建于PostgreSQL之上

关键在于,这些公司早已不再以2005年的方式来使用PostgreSQL。

🚀 队列系统:告别Redis与RabbitMQ

PostgreSQL原生支持LISTEN/NOTIFY机制,其作业队列的处理能力甚至优于许多专用方案:

sql

-- 基于PostgreSQL的轻量级作业队列
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;

这种方式天然支持精确一次(Exactly-Once)处理语义。相比之下,用Redis实现相同功能将面临诸多挑战。

在UserJot中,我正是采用这种模式来处理反馈提交、通知发送和路线图更新等场景。单一事务即可确保一致性,完全无需引入消息代理的复杂度。

💾 键值存储:Redis的替代方案

各大云平台的Redis服务起价约为20美元/月。而PostgreSQL的JSONB功能已内置于您现有的数据库中,足以应对大多数使用场景:

sql

-- 实现键值存储的替代方案
CREATE TABLE kv_store (
    key VARCHAR(255) PRIMARY KEY,
    value JSONB,
    expires_at TIMESTAMP
);

-- 为JSON查询创建GIN索引
CREATE INDEX idx_kv_value ON kv_store USING GIN (value);

-- 支持嵌套JSON的高效查询
SELECT * FROM kv_store
WHERE value @> '{"user_id": 12345}';

@>操作符是PostgreSQL处理JSON的利器,其查询性能甚至超越多数NoSQL数据库,同时保持数据一致性。

🔍 全文搜索:Elasticsearch并非必需

Elasticsearch集群不仅成本高昂,维护也相当复杂。PostgreSQL内置的全文搜索功能已经足够强大:

sql

-- 为任意表添加搜索功能
ALTER TABLE posts ADD COLUMN search_vector tsvector;

-- 自动更新搜索索引
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;

-- 支持相关性排序的搜索结果
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集群。

📡 实时功能:简化WebSocket架构

基于PostgreSQL的LISTEN/NOTIFY机制,您可以轻松实现实时更新,无需额外的基础设施:

sql

-- 向客户端推送变更通知
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美元/月

  • 三项服务的监控:30美元/月
    总计:每月125美元

但这仅仅是托管成本,真正的痛点在于:

运维复杂度

  • 需要监控、更新和调试三种不同的服务

  • 各自独立的扩展模式与故障模式

  • 多套配置需要维护

  • 分离的备份与灾难恢复流程

  • 每项服务都有不同的安全考量

开发复杂度

  • 不同的客户端库和连接模式

  • 多服务协同部署

  • 数据一致性问题

  • 复杂的测试场景构建

  • 不同的性能调优方法

如果您选择自托管,还需要额外承担服务器管理、安全补丁更新,以及Redis在凌晨3点突然内存泄漏时的紧急调试。

而PostgreSQL让您通过单一服务管理所有功能。

📈 单一数据库的扩展能力

许多人尚未意识到:单个PostgreSQL实例就能够处理惊人的负载——我们说的是每日数百万事务、TB级数据存储和数千个并发连接。

真实世界的例证:

  • Airbnb:单个PostgreSQL集群处理数百万笔预订

  • Robinhood:支撑数十亿金融交易

  • GitLab:完整的DevOps平台基于PostgreSQL

PostgreSQL的架构设计极具魅力,它具备卓越的垂直扩展能力。当您最终需要水平扩展时,成熟的方案包括:

  • 基于读副本的查询扩展

  • 大表分区

  • 连接池优化

  • 逻辑复制构建分布式架构

绝大多数企业永远达不到这些扩展极限。在真正需要应对数百万用户或复杂分析工作负载之前,单个实例通常绰绰有余。

对比之下,管理多个以不同方式扩展的独立服务——Redis可能内存不足,消息队列遭遇吞吐量瓶颈,搜索服务需要完全不同的硬件配置——这种复杂度是完全可以避免的。

🛠️ 从第一天起避免过度设计

现代软件开发的最大陷阱是“宇航员架构”——我们为从未遇到过的问题、从未见过的流量规模、可能永远达不到的性能要求而过度设计系统。

典型的过度设计循环:

  1. “我们某天可能需要扩展”

  2. 引入Redis、消息队列、微服务、多数据库

  3. 花费数月调试集成问题

  4. 向47个用户发布产品

  5. 每月支付200美元的基础设施费用,而这些完全可以在5美元的VPS上运行

与此同时,您的竞争对手因为不在需要分布式系统之前就管理分布式系统,而能够更快地交付产品。

🏆 更明智的技术选型策略

  1. 从PostgreSQL开始——抵制添加其他数据库的冲动

  2. 善用JSONB获得灵活性——在享受无模式开发便利的同时,保留SQL的强大能力

  3. 在PostgreSQL内实现队列——节省成本并降低复杂度

  4. 仅在达到实际瓶颈时引入专用工具——而非想象中的瓶颈

📝 实践经验分享

UserJot的开发过程成为这一理念的完美验证。作为一个反馈和路线图工具,它需要:

  • 提交反馈时的实时更新

  • 针对数千个功能请求的全文搜索

  • 发送通知的后台作业

  • 频繁访问数据的缓存

  • 用户偏好和设置的键值存储

我的整个后端仅使用一个PostgreSQL数据库。没有Redis,没有Elasticsearch,没有消息队列。从用户认证到实时WebSocket通知,一切均由PostgreSQL处理。

结果如何?我能够更快地交付功能,需要调试的组件更少,基础设施成本降至最低。当用户提交反馈、搜索功能或获取路线图变更的实时更新时,所有操作都由PostgreSQL高效完成。

这不再是理论探讨,而是经过真实用户和数据验证的生产实践。

💡 核心洞察

PostgreSQL的强大之处在于它能同时担任您的主数据库、缓存、队列、搜索引擎和实时系统——同时在所有层面保持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上实现相同的原子性操作,您将深刻体会到其中的差异。

🎯 务实的技术选择

PostgreSQL可能不够“炫酷”,它没有华丽的官网,也不会在TikTok上病毒式传播。但在其他数据库兴起又衰落的几十年间,它始终默默地支撑着互联网的发展。

选择简单、可靠且高效的技术,本身就是一种智慧。

行动建议
当下次有人建议添加Redis来“提升性能”或引入MongoDB来“增加灵活性”时,不妨反问:“您是否真的尝试过在PostgreSQL中实现这个需求?”

答案可能会让您惊讶。就我个人而言,基于PostgreSQL构建UserJot的体验证明:简单而专注的技术选择,往往能带来最稳健的产品基础。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐