最近在做系统架构优化的时候,我一直在思考一个问题:Next.js + Nginx + PostgreSQL 这套基础三板斧,真的足够支撑高并发吗?
答案是:远远不够。单就这几项,在处理真正的流量洪峰时,会有很多能力缺口。今天想分享一下我在实际项目中总结的一套"组合拳",从应用、数据库到架构层面,帮大家把高并发场景下的系统能力补全。
基础三板斧的优化
先说现有架构能做什么优化(这部分开源免费,立即可做):
Next.js 层
- 数据库连接改成单例模式,避免重复创建连接池的开销
- 借助 ISR(增量静态再生)把高频访问的页面预渲染成静态文件
- 使用流式渲染(Streaming),让页面骨架逐步吐出,缓解 SSR 压力
Nginx 层
- 从单纯的反向代理升级为负载均衡器
- 开启 Gzip 压缩和静态资源强缓存
PostgreSQL 层
- 单表过大时建议做分区
- 为高频查询字段建立索引
- 调整关键内存参数:
shared_buffers设为物理内存 25%、work_mem128MB、maintenance_work_mem2GB - 使用连接池 PgBouncer
- 低峰期执行
VACUUM ANALYZE清理死元组
必须引入的额外技术
但上面这些只是基础。以下三项,是我在经历过流量高峰后,认为必须引入的:
| 技术 | 解决的痛点 | 为什么"高并发"缺了它不行 |
|---|---|---|
| Redis | 多实例缓存不一致、数据库被读请求打崩 | 横向扩展后,每个实例的本地缓存彼此独立,会导致数据混乱。Redis 提供统一的缓存层,所有实例共享一份缓存。 |
| 消息队列 (如 BullMQ) | 高耗时任务阻塞 HTTP 线程、尖峰流量压垮系统 | 当并发超出数据库处理能力时,新请求直接拒绝或排队。队列能将突发请求削峰填谷,让后端按节奏处理。 |
| 读写分离 (如 Pgpool-II) | 数据库单点读写瓶颈 | 将查询操作分流到只读从库(Replica),写操作留在主库。 |
Redis:不只是缓存
在我目前的项目里,Redis 承担了三件事:
- 全栈缓存 —— 把 Next.js 的渲染结果或 API 响应缓存在 Redis 中,直接绕过数据库
- 会话共享 —— 用户登录状态统一存 Redis,多实例之间共享
- 队列后端 —— 配合 BullMQ,把异步任务丢进队列处理
消息队列:流量削峰的利器
对于 AI 生成类的场景特别有用:
- 收到生成请求时,立即返回一个队列 ID
- 前端轮询状态,或者任务完成时推送通知
- 用户不用一直等待,系统也不会因为突增请求崩溃
另外,把耗时任务(报表生成、图片处理)交给队列后,主线程可以立刻释放,响应新请求。而且队列自带持久化,服务重启后任务也不会丢失。
读写分离:解耦数据库压力
- 通过增加只读实例来线性提升读性能
- 主库专注写入和强一致性读
- 需要注意主从复制延迟,确保读操作能容忍少量延迟
完整架构图
flowchart LR
User[用户] --> LB[Nginx 负载均衡器]
LB --> App1[Next.js 实例1]
LB --> App2[Next.js 实例2]
LB --> App3[Next.js 实例...]
App1 --> Redis[(Redis 集群<br/>缓存/会话/队列)]
App2 --> Redis
App3 --> Redis
App1 --> Queue[消息队列<br/>BullMQ]
App2 --> Queue
App3 --> Queue
Queue --> Worker[后台Worker进程]
Worker --> Cache[(Redis / 数据库)]
App1 --> PgPool[读写分离中间件<br/>Pgpool-II]
App2 --> PgPool
App3 --> PgPool
PgPool --> Master[(PostgreSQL 主库<br/>处理写入)]
PgPool --> Replica1[(PostgreSQL 从库1<br/>处理查询)]
PgPool --> Replica2[(PostgreSQL 从库...<br/>处理查询)]
style Redis fill:#f9f,stroke:#333,stroke-width:2px
style Queue fill:#bbf,stroke:#333,stroke-width:2px
style PgPool fill:#bfb,stroke:#333,stroke-width:2px
这张图是我目前在用的架构:Nginx 负载均衡 + Next.js 应用层 + Redis(缓存/队列/会话)+ 后台 Worker + Pgpool-II + PostgreSQL 主从集群。
什么时候必须引入?
基于我的经验,给大家一个判断标准:
必须引入
- Redis:只要 Next.js 应用 ≥2 个实例,就必须用 Redis 做共享缓存,否则会出现缓存不一致和流量风暴
- 读写分离:当数据库 读请求 QPS > 2000,或 CPU 长期 > 70% 时,必须引入
- 消息队列:当请求中包含耗时 > 500ms 的任务(如图片生成、报表导出),或者后端服务无法水平扩展时,必须引入
看情况引入
- Elasticsearch:PostgreSQL 的
LIKE查询在大数据量下很慢,当搜索需要毫秒级响应时引入 - CDN:面向全球用户,或包含大量静态资源(图片、视频)时引入
- InfluxDB:当监控/日志数据量很大,且主要是写入和范围查询时引入
我的高并发优化路线图
如果你也是 Nginx + Next.js + PostgreSQL 架构,可以参考我这套演进路线:
第一周(P0,最高优先级)
- 代码层优化:数据库连接单例、ISR、流式渲染
- Nginx 负载均衡配置
- 接入 PgBouncer 连接池
第二周(P1,高优先级)
- 接入 Redis 缓存
- 实现会话共享
- 优化 PostgreSQL 索引和查询
第三周(P2,中优先级)
- 搭建数据库一主多从
- 接入 pgpool-II 实现读写分离
- 配置主从延迟监控
第四周及以后(P3,逐步实施)
- 搭建 消息队列(BullMQ + Redis) 处理耗时任务
- 复杂搜索接入 Elasticsearch
- 全球业务配置 CDN
写在最后
高并发架构的演进是逐步的,不要试图一次性引入所有技术。先解决最痛的点,再不断完善。
我在实际踩坑中发现,很多时候系统的瓶颈并不在代码本身,而是在架构层面的缺失。希望这套组合拳能帮到你。