☰
从单机到分片:PostgreSQL支撑8亿用户的架构演进
2026/10/9 3:42:30 网站建设 项目流程

做过几年数据库内核相关的工作,后来也一直在业务团队管高并发系统,每次看到“XX支撑8亿用户”这种标题,第一反应不是兴奋,是先算账。8亿用户这个量级放到数据库头上,本质上不是“能不能用PostgreSQL”的问题,而是“怎么用”的问题。我见过太多人把扩展方案聊成玄学,动不动就上分库分表、分布式中间件,结果连单机瓶颈在哪都没搞清楚。

这篇文章我打算把“8亿用户”这个数字彻底拆开,变成一组可量化的负载指标,再基于PostgreSQL的特性,把从单机优化到读写分离、连接池、分片乃至缓存配合的完整路线捋一遍,最后聊几个真实项目里最容易被低估的坑。整个过程不推崇拜某个中间件,也不鼓吹“PostgreSQL无敌”,只讲实际工程中验证过、且逻辑能自洽的做法。

1. 先算一笔账:8亿用户到底在考验哪几个数字

ChatGPT这类产品有个特点:它不是传统意义上的OLTP系统,也不是纯粹的数据仓库,而是介于两者之间——大量读、大量写、Session状态持续刷新、大字段(对话上下文)反复读取。8亿注册用户背后,数据库层要扛的是几个非常具体的指标,先把账算清楚,后面所有方案才有依据。

1.1 每秒查询数:把“用户量”翻译成数据库语言

假设8亿是注册用户,活得比较活跃的可能只有20%到30%,也就是每天大概1.6亿到2.4亿人真正打开产品。再按一天当中有显著峰谷的规律,比如峰值时段占全天流量的20%,那峰值小时可能要处理几千万次请求。粗糙估算下来,数据库层(包括缓存和DB)峰值至少要支撑每秒百万级QPS。

百万QPS听起来吓人,但要注意两点:第一,这里面大量是读请求,而且大部分可以被Redis这类缓存挡住;第二,真正落到PostgreSQL的写请求,会低一个数量级。ChatGPT的核心交互是用户发消息、模型返回结果,一次对话会产生1条消息记录、若干条Token级别的内部日志、一次订阅/配额校验,同时还有大量读操作在查历史会话、查上下文。乐观一点估算,写密集的部分峰值可能需要每秒1到3万的TPS,读请求在缓存失效、首次加载、直接查库的场景下,每秒五六十万次也很正常。

这个数字放到单机PostgreSQL上,哪怕是顶配硬件,也会在一分钟之内被打穿。这也是为什么题目里“扩展”这两个字才是重点——不是调参就能解决的,要改架构。

1.2 数据量与存储增长:从GB到PB只差一个规模系数

用户量大的产品,最容易被忽视的是数据增长速度。假设只有两亿活跃用户,每人每天平均产生500条消息和日志记录,一天就是千亿行级别的写入。这显然不是所有行都要永久保存在核心库里,90%以上的日志、中间状态、Token级数据是要走归档或冷存储的。真正热的数据可能是用户会话、消息主记录、计费事件,粗算下来一天几个亿行。

如果每天净增几十GB到几百GB(取决于保留策略),半年到一年后核心库就会到几十TB。注意,这个数据量下,单表如果还是普通堆表,不加分区、不做冷热分离,连日常查询都会开始变慢,更别说备份恢复、索引维护这些运维动作。存储扩展不是“加块硬盘”的事情,而是要从第一天就设计好数据生命周期,不然三个月后你就得一边扛线上流量一边做迁徙,那是所有DBA的噩梦。

1.3 连接数:最致命、最少被人提前想到的指标

数据库的连接数和用户数之间有个典型的放大关系。应用层每个实例可能维持几百到几千个连接池连接,而ChatGPT这种体量,后端服务实例数量可能是几千个,如果每个实例的PG连接池开200,那总量就是几十万级。

PostgreSQL的默认进程模型是一个连接对应一个后端进程,这几万个进程光上下文切换就能把CPU吃光。在8亿用户的场景里,“连接管理”是不管怎么扩展都要面对的瓶颈,它甚至比分片更优先要解决,因为不解决连接数,你连分片的基础都打不好。先记住这个结论,后面专门展开。

2. 单机PostgreSQL的瓶颈到底藏在哪里

很多人对“PostgreSQL能不能支撑大规模”的讨论,其实聚焦错了方向。PostgreSQL本身的内核能力在开源数据库里是非常强的,单机瓶颈不是“不够用”,而是“资源模型决定了它有一个明确的天花板”。分清楚这个天花板是什么,才能知道扩展该往哪个方向去。

2.1 四类资源:CPU、内存、磁盘、连接

CPU方面,PostgreSQL的查询执行、表达式计算、MVCC版本判断、位图扫描这些都是CPU密集的。在百万QPS的场景下,哪怕一半请求被缓存挡住,落到数据库的读请求仍然是几十万级每秒,单机CPU核数哪怕是64核、96核,每个核每秒能处理的简单查询也就几百到一千次,乘出来基本就是单机上限。

内存方面,核心是shared_buffers和操作系统Page Cache的配合。PostgreSQL的shared_buffers通常不建议超过服务器内存的1/4到1/3,原因是大量共享内存管理本身有开销,而且剩余内存还需要留给后端进程的私有内存和文件系统的Page Cache。如果工作集超过内存容量,命中率下降,每次查询都走磁盘,性能直接垮掉。

磁盘方面,现在的NVMe SSD能提供很高的IOPS,但PostgreSQL的同步提交每笔事务都要等WAL刷盘,即便用组提交,物理限制也在那里——单机WAL写入带宽再快,也不可能支持每秒几万事务的同步提交而没有任何排队。异步提交能缓解,但代价是丢数据的窗口,这在ChatGPT这种产品上不是能不能接受的问题,而是产品逻辑允不允许的问题。

连接方面,前面提过,每个客户端连接对应一个约10MB左右的后端进程,连接数一旦过千,光内存就是十多个GB起步,上下文切换、锁等待、系统调用全部恶化。这是单机PG最容易被忽略也最提前碰到的墙。

2.2 WAL写入与Checkpoint:决定写性能的物理极限

PostgreSQL的写路径,任何DML都要先写WAL日志,然后才改数据页,最后在Checkpoint的时候把脏页刷入数据文件。WAL是顺序写,理论上是SSD最擅长的场景,但同步提交要求每个提交的LSN必须刷到持久化存储,所以每秒能提交的事务数,取决于WAL写入带宽除以每事务平均产生的WAL大小。

假设每笔事务平均产生5KB WAL,一块高性能NVMe盘的顺序写带宽大概2GB/s,理论峰值是每秒40万笔,但是注意,这是整块盘的极限,而且能到这个速度的还要求没有其他IO竞争。真实情况下,每笔事务产生的WAL可能更多,加上数据页读取、索引更新、脏页刷盘、autovacuum后台读写互相争抢,单机能稳稳扛住的写TPS大概就是几千到一两万,而且还是在“库很小、没有索引过热、配置合理”的理想状态下。

Checkpoint是另一个隐形杀手。每完成一个检查点周期,要把所有脏页刷盘,这个瞬间会产生大量IO,造成周期性尖峰。如果写入速率很高,checkpoint刷盘的峰值就可能和业务IO叠加,导致延迟毛刺。在高并发系统里,毛刺比平均延迟更让人头疼。

2.3 结论:单机优化到极致是什么水平

把配置调好、SQL优化好、索引建好,一台顶配单机PostgreSQL大概能做到什么程度?我见过比较稳的实际水平是:读多写少的场景下,混合负载大概1到2万TPS写入,10到20万QPS的点查读,前提是内存足够放下全部热数据、磁盘全SSD、应用层连接池开得合理。

这是单机物理极限,不是“调参不够努力”。所以真正的扩展,只能在架构层面做横向拆分——让几十台甚至几百台PostgreSQL各自承担一部分流量,而不是盯着某一台机器的参数反复调。想通这一点之后,后续方案就顺理成章了。

3. 从单机走向集群:横向扩展的完整路径

PostgreSQL横向扩展的路线,按我自己的经验,应该分三步走:读写分离解决读压力,连接池解决连接风暴,分片解决写和数据的最终规模。这三步有先后顺序,前两步做扎实之后,分片的复杂度和风险都会显著降低。

3.1 第一步:读写分离,把读流量从主库拆走

PostgreSQL从9.0开始引入流复制(Streaming Replication),现在已经是所有高可用方案的标配。主库处理写入,通过WAL实时传给从库,从库可以接受读请求。这套机制的关键点在于:复制延迟的控制、从库的负载均衡、读请求的分配策略。

在ChatGPT这类场景里,读流量占比可能超过90%,把读分流到从库,主库的压力会立刻下降一个数量级。但有几个细节必须处理好:

  • 复制延迟:同步复制(synchronous replication)能保证主从数据一致,但会降低写入的可用性和吞吐;异步复制有毫秒级延迟,适合对一致性要求不敏感的场景。ChatGPT这种产品,会话消息的写入和后续读取之间可能间隔几百毫秒以上,异步复制完全够用。但如果是“写后立刻读”的关键路径,比如刚创建订阅就要立即校验,就需要走主库或使用会话级路由。
  • 从库数量:别一开始就挂二十个从库。从库太多,主库的WAL发送网络开销也会成为负担。实践上两个到四个从库通常是甜点区,如果还不够,应该在缓存层解决,而不是无限加从库。
  • 读负载均衡:应用层需要知道哪些查询可以走从库、哪些必须走主库。我当时做的方式是在数据访问层包一个路由,把强一致请求打主库,弱一致请求随机打到从库池。不要用中间件自动判断事务里的读写,那往往不够灵活。

读写分离不会降低单库数据量,但它能非常有效地把读吞吐推上去。8亿用户场景里,只要缓存和读写分离配合好,读流量这一关基本能过。

3.2 第二步:连接池,先把进程模型跑通

前面提到PostgreSQL的一个连接对应一个进程,连接数一多,CPU全部浪费在上下文切换上。解决这个问题的标准工具是PgBouncer,它作为数据库和应用之间的代理,把客户端连接复用到一小批真实数据库连接上。

PgBouncer有三种模式:

  • Session模式:客户端连接和PgBouncer到数据库的连接绑定整个生命周期,本质上只是把连接前移,省掉建连开销,但无法解决大量并发连接占满后端进程的问题。
  • Transaction模式:每个事务执行时才从池子里取数据库连接,事务结束立即归还。这是最常用的模式,可以让几百个应用实例共享几十个数据库连接。
  • Statement模式:每个SQL语句级别取连接,适合无状态的简单查询,但像游标、临时表这种场景会不兼容,所以一般少用。

线上我推荐用Transaction模式,配置文件很简单:连接池大小、空闲超时、服务端空闲检测。重点说两个容易被坑的点:第一,PgBouncer自身可能成为单点,所以要么在每台应用服务器本地部署(Local PgBouncer)避免额外一跳,要么用集群方案(比如和HAProxy配合或直接用支持集群的连接池方案)。第二,连接池大小不是越大越好,每个池子里的连接数超过一个阈值后,事务排队时间反而增加,一般每个PgBouncer后端连接数设置为CPU核数的4到8倍,先跑压测观察延迟曲线再调。

追加一步:应用层的连接池(如Java的HikariCP、Go的pgxpool)也应该设置合理上限,避免应用实例无限申请数据库连接。连接池是分层设计的,应用层连接池负责应用内的连接复用,PgBouncer负责把多个应用实例的连接收敛到数据库可承受的范围内。

3.3 第三步:分片,最后的大招

读写分离和连接池能解决“读”和“连接数”两个指标,但解决不了“单库数据量”和“写TPS上限”的问题。这时候分片(Sharding)就是绕不开的扩展方式。

分片方案有几种主流选择:

  • 原生分区 + 应用层路由:PostgreSQL本身支持分区表,但你得自己决定数据落到哪个分区,这个决定通常在应用层通过分片键算出。比如ChatGPT场景,按照用户ID哈希分片,每个分片是独立的PostgreSQL实例或一个实例上的独立数据库,应用层通过分片键路由到对应的库执行。
  • Citus:扩展插件,能把多台PG节点组织成一个逻辑集群,支持分布式表、分布式查询、分布式DDL,对应用层比较友好。它的核心是让用户显式指定分布键(distribution column),然后Coordinator节点负责路由和合并结果。
  • 面向多租户的自动分片:如果产品天然是多租户结构(比如ChatGPT的每个用户就是一个租户),分片策略可以非常清晰——按租户分片,一个租户的所有数据落在同一分片上,这样事务都在单分片内完成,跨分片事务几乎不会出现。

分片听上去是“把表拆到多台机器”,但真正的复杂度在于:分片键的选择、跨分片查询的处理、分布式唯一ID、数据迁移与扩容。这个后面单独展开。

我不想把分片鼓吹成“银弹”。分片是最后的手段,因为它带来的运维复杂度是几何级上升的。如果读写分离加缓存能把QPS扛住,数据量确实单库能放下,那我宁可少分片。但8亿用户、PB级数据、每天几亿行的写入,老老实实承认:不分片是走不下去的,问题只在“怎么分”。

3.4 分片架构设计中的关键取舍

分片键选什么,是整个架构里最不能改的决策。改分片键等于重写架构。我的经验是:分片键必须满足三个条件——业务上天然稳定、能均匀分布数据、应用层绝大多数查询都带得上的字段。ChatGPT场景下,user_id就是最合适的分片键,因为几乎所有查询都有用户上下文(查会话列表、查消息、做配额校验),天然满足“查询必带分片键”的要求。

分片后最痛苦的事情是跨分片操作。比如“全局搜索所有用户的消息记录”,这必须把查询广播到所有分片再合并结果,性能和复杂度都很难办。这种情况下要么引入搜索引擎做全局索引,要么在产品层限制这类跨分片查询(比如只允许在单个会话内搜索)。

分片还有一个容易被忽略的问题是数据倾斜。按用户ID哈希分片理论上均匀,但如果头部用户占全量流量的大头(超级重度用户),哈希分片也救不了你。所以某些高并发场景下,可能需要把头部用户单独拆出来放专属分片,或者给头部用户建独立的缓存层,避免一个分片被打爆拖垮整体。

4. 让数据库只干数据库的活:缓存与异步化

扩展PostgreSQL的另一个思路,是减少PostgreSQL需要处理的事情。这听起来像废话,但大多数团队在实际操作中,会把一堆本该由缓存、队列、搜索引擎处理的流量,直接压到数据库头上,然后得出结论“PostgreSQL不行”。其实不是数据库不行,是职责没分清楚。

4.1 缓存不是可选项,是架构的必需品

在8亿用户的场景里,Redis这类缓存不是“优化手段”,而是主路径的一部分。以ChatGPT为例,哪些数据适合放缓存?

  • 高频读、低频变的数据:比如功能开关、模型列表、价格配置、用户订阅状态(短暂允许过期),这些可以全量放缓存,数据库只负责变更时更新。
  • 会话的热数据:最近N条对话消息、当前正在处理的Context窗口,这些是每秒钟可能被读取多次的,而且读取路径上有严格延迟要求。Redis直接把这个延迟从几十毫秒降到个位数毫秒。
  • 限流与配额:ChatGPT有按小时、按天的使用限额,这个不能用数据库每次访问都去实时计算,正确做法是计数器放Redis,窗口过期后异步回写数据库。

缓存层要担心的不是“要不要用缓存”,而是缓存下探导致数据库瞬时流量尖峰,也就是缓存击穿、穿透、雪崩这三件事。我贴一个简单但有效的处理思路:

  • 击穿(热点key过期):热点key不设置过期时间,改为后台异步刷新;或者过期时用互斥锁让只有一个请求去重建缓存。
  • 穿透(查询不存在的数据):布隆过滤器挡在缓存前面,或者对空结果也做短暂缓存,比如存一个空值并设置较短TTL。
  • 雪崩(大量key同时过期):过期时间加随机抖动,别让一堆key在同一秒失效。

8亿用户场景里,缓存层的吞吐能力通常要比数据库高一到两个数量级,而且成本低得多。把读流量尽量留在缓存层,这是PostgreSQL能够“撑住8亿用户”的前提之一。

4.2 异步写:把峰值抹平

不是所有数据都需要同步落库。以ChatGPT场景为例,用户每发一条消息,会产生消息记录、Token用量、计费事件、内部审计日志等好几类数据。其中真正需要立刻同步写入、并参与后续事务的,可能只有消息主记录本身。Token用量和日志类数据,完全可以先推到Kafka等消息队列,由消费者批量写入数据库。

异步化的收益很直观:数据库面对的不再是瞬间万级TPS的写入尖峰,而是相对平滑的批量写流量。这能显著降低Checkpoint频率、WAL写入压力、锁竞争。代价是增加了消息队列这个组件,以及“数据最终一致”的窗口期。比如用户刚发完消息立刻查看Token用量,可能还没更新——这种场景在产品上做一个“用量稍后更新”的暗示就能接受。

我自己在项目里的做法是:把写数据分成三类——强一致同步写、可接受毫秒级延迟的准实时写、可接受分钟级延迟的异步写。前两类直接走数据库主库和从库,第三类走队列+批量任务。这样做完,数据库的写峰值能降一半以上,效果立竿见影。

4.3 冷热分离与归档:控制数据增量

回到数据量问题。PB级数据如果全部放在热数据库里,不管分多少片,硬件成本和运维成本都是灾难。正确思路是定义数据温度:

  • 热数据:最近7天的会话上下文和活跃用户的消息记录,放主存储,服务实时读写。
  • 温数据:最近3个月的数据,可以放到成本更低的存储或压缩后放在从库/分析库,用于历史查询。
  • 冷数据:超过3个月的消息、日志、审计数据,转到对象存储或归档数据仓库,不参与在线查询。

PostgreSQL的声明式分区非常适合作这个生命周期管理。按月分区的表,在分区过期后执行一次detach,然后把底层表转成归档,整个操作对在线写入几乎无感。比如这种写法:

CREATE TABLE messages ( id bigserial, user_id bigint NOT NULL, conversation_id bigint, content text, created_at timestamptz NOT NULL DEFAULT now() ) PARTITION BY RANGE (created_at); CREATE TABLE messages_2025_04 PARTITION OF messages FOR VALUES FROM ('2025-04-01') TO ('2025-05-01'); ALTER TABLE messages DETACH PARTITION messages_2025_03;

这个方案能让你把在线库体量控制在一个可预期的范围内,同时让数据库引擎真正只处理热数据,性能自然稳定。很多团队一上来就搞分片,结果分片库里的冷数据照样堆积,搞得每个分片都臃肿无比,其实冷热分离做好了,数据量的压力能化解很大一部分。

5. 真实世界的参照:亿级用户使用PostgreSQL是怎么做的

光讲理论和方案,容易让人觉得是纸上谈兵。这里我聊几个公开可查的真实案例,他们的选择能帮我们校准思路——不是“PostgreSQL能不能撑8亿用户”的问题,而是“在什么条件、用什么架构下撑”。

5.1 Instagram:垂直扩展被低估的时期

Instagram早期有约3000万用户时,整个后端就跑在几台托管PostgreSQL实例上,主库数据量几个TB,没有分片,靠的是读写分离、缓存以及一堆非常精细的单机优化。当时他们甚至跑在EC2上,SSD还不普及,能撑下来完全是靠:把绝大多数读请求推到Redis、把写入路径尽量简化、垂直扩展(换更大内存更多CPU的实例)达到极限后才开始考虑分片。

这个案例给我的启发是:别过早分片。分片带来的复杂度是真实的,晚一天分片,你就多一天不需要处理分布式的额外复杂度。但Instagram后来用户量到几亿时也分片了,这说明分片不是可选项,只是时间点问题。

5.2 分片先行:多租户产品的天然边界

另一个极端是像Discord这类产品,早期用PostgreSQL支撑了非常大的规模,到某个阶段后开始把数据结构化迁移。Discord官方技术博客分享过,他们用PostgreSQL外加数据仓库方案支撑过亿级用户,消息量级从千万级增长到亿级。他们走的是:普通业务走PostgreSQL,消息历史这类超大规模社交数据量单独设计架构。

这类案例的共同点是:PostgreSQL在整个技术栈里扮演“核心业务可靠存储”的角色,而不是所有数据的唯一容器。消息、日志、行为数据这些超大规模、低一致性要求的维度,交给专门的系统;而用户、订单、权限、会话元数据这些强一致要求的数据,留在PostgreSQL里做精做强。

5.3 托管数据库的扩展实践

碰到过很多团队直接跑在云托管的PostgreSQL上,比如RDS、Cloud SQL一类。这些托管服务天然提供了只读副本、自动备份、跨可用区容灾,管理成本低很多。但要提醒一点:托管服务不解决架构问题,它只是把单机和主从层的运维自动化了。一旦流量到了必须分片的阶段,你仍然得自己设计分片方案,或者换到具备分布式能力的托管形态。

ChatGPT层面,OpenAI一直有PostgreSQL作为核心数据存储的公开信息,且因为流量巨大,他们在基础设施上做了大量定制。这恰恰印证了:PostgreSQL不是不能打,而是需要一套完整配套的架构去支撑,数据库本身只是这盘棋里的一个子。

在真实案例的参照下,我的结论是:PostgreSQL在亿级用户系统里既能当核心库,也不过是复杂分布式系统的一个组件。把它当万能存储是错误,把它当玩具也是错误。

6. 扩展道路上最容易被低估的几个坑

最后来聊实操中容易翻车的地方。这一节不是教科书里的内容,都是我在真实项目里踩过、或者见过同行踩完之后复盘出来的。

6.1 分片后的事务与全局唯一ID

分片最直接的冲击是事务边界。原本一个事务里可以同时更新用户表和消息表,现在这两张表可能在不同分片里,跨分片事务要么用两阶段提交(2PC,成本很高),要么在应用层做事务消息、补偿逻辑。ChatGPT这类场景相对幸运,因为以user_id为分片键后,同一个用户的所有操作都落在同一分片上,传统ACID事务可以完整保留。这一点在选分片键时就要想清楚:宁可牺牲一些均衡性,也要让核心事务全部在单分片内完成。

全局唯一ID在分片后也是个坑。PostgreSQL的序列(Sequence)在主节点上是唯一的,但分片后每个分片有自己的序列,就会产生冲突。常见做法有两种:一种是使用UUID v7这类基于时间和随机性的分布式ID,另一种是给每个分片配置不同的序列起点和步长,比如分片1取1、3、5,分片2取2、4、6。前者更推荐,因为它天然无序可排序,而且不会因为分片扩容需要重新规划。

6.2 PostgreSQL膨胀、autovacuum与索引维护

PostgreSQL的MVCC机制决定了更新和删除会留下死元组(dead tuples),需要autovacuum回收。高TPS场景下,如果autovacuum跟不上产生死元组的速度,表就会膨胀,查询变慢,索引空间翻倍。很多团队在做完分片后,发现单分片性能依然不稳,排查半天才意识到是膨胀问题。

这个坑的规避方式不算复杂,但要重视:关注pg_stat_user_tables里的n_dead_tup和last_autovacuum字段,对高频更新的表要主动调整autovacuum参数,必要时给关键表做周期性的手动VACUUM。另外,在分片场景下,热表如果长时间重写数据,会造成索引的写放大,建议定期重建高写入表的索引,比如:

REINDEX TABLE CONCURRENTLY messages;

这条命令不会锁表,线上可以用。否则你会在某个周末接到告警:所有查询都变慢了,然后发现索引比表本身还大。

6.3 连接风暴与雪崩:数据库层的“最后一根稻草”

前面说过连接数和进程模型的关系,这里讲一个具体场景。很多团队在流量高峰期,因为某次慢查询拖慢了数据库整体响应,应用层连接池里的连接被占满,新请求不断排队,最终连接池增长到数据库上限,数据库彻底拒绝新连接,然后所有服务一起雪崩。

PostgreSQL的max_connections设得过高反而危险——它会让系统在负载下退化成大量进程争抢CPU。我建议的处理方式:

  • max_connections设置一个合理上限,比如500到1000(具体看单机内存)。
  • 连接都走PgBouncer,让应用层拿到的连接是“租来的”,而不是PostgreSQL的真实连接。
  • 对慢查询设置statement_timeout,避免一个慢SQL占着连接不释放。
  • 靠监控及时观察连接数增长率,提前扩容或限流。

连接风暴是架构层面一个不起眼但破坏力巨大的问题。数据库扩展不只是“加机器”,也包括把连接管理、语句超时、队列削峰这些“防御性机制”做到位。

6.4 变更表结构:锁、迁移与发布节奏

8亿用户的系统里,哪怕是在线加一个索引,都可能拖垮全库。PostgreSQL的加索引如果不用CONCURRENTLY,会锁住整张表,所有写请求排队。你以为你只是“加个索引”,实际上用户在默默等待。这种事故我在不止一家公司见过。规范做法是:

  • 所有DDL都要走自动化审查流程,评估锁的影响范围。
  • 加索引用CONCURRENTLY,虽然耗时更长,但不阻塞读写。
  • 添加字段时尽量避免给大表设置非空默认值(PostgreSQL 11+在特定场景有优化,但并非万能),分批次、低峰期操作。
  • 大表的表结构变更,甚至要先考虑用分区表加新表再切换的方式,尽可能减少对主表的重写。

架构扩展是长期的过程,但表结构变更贯穿整个过程,任何一步不小心都可能让之前的所有扩展工作白费。保持敬畏,线上一切操作先看锁等待。

如果让我给一个务实的落地顺序,我会这样建议:第一步,先做读写分离和缓存,把读流量移走;第二步,上连接池,卡住连接数上限;第三步,做冷热分离和异步化,控制住数据量与写峰值;第四步,等单库真的到瓶颈了,再按user_id分片。每一步做完,都要用压测验证,确认瓶颈确实转移到下一个环节后再动手,而不是提前把复杂度拉满。我在实际项目中经历过“过早分片导致跨片查询天天报错”的窘境,也见过一套读写分离加缓存就稳稳扛住千万DAU的系统,所以我对“分片是万灵药”这个说法始终保持警惕。PostgreSQL撑住超大规模用户,从来不是某一招的胜利,而是架构分层、流量治理、可观测性这些基本功的综合结果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询