Next.js 高并发架构组合拳实战

16 阅读4分钟

最近在做系统架构优化的时候,我一直在思考一个问题:Next.js + Nginx + PostgreSQL 这套基础三板斧,真的足够支撑高并发吗?

答案是:远远不够。单就这几项,在处理真正的流量洪峰时,会有很多能力缺口。今天想分享一下我在实际项目中总结的一套"组合拳",从应用、数据库到架构层面,帮大家把高并发场景下的系统能力补全。


基础三板斧的优化

先说现有架构能做什么优化(这部分开源免费,立即可做):

Next.js 层

  • 数据库连接改成单例模式,避免重复创建连接池的开销
  • 借助 ISR(增量静态再生)把高频访问的页面预渲染成静态文件
  • 使用流式渲染(Streaming),让页面骨架逐步吐出,缓解 SSR 压力

Nginx 层

  • 从单纯的反向代理升级为负载均衡器
  • 开启 Gzip 压缩和静态资源强缓存

PostgreSQL 层

  • 单表过大时建议做分区
  • 为高频查询字段建立索引
  • 调整关键内存参数:shared_buffers 设为物理内存 25%、work_mem 128MB、maintenance_work_mem 2GB
  • 使用连接池 PgBouncer
  • 低峰期执行 VACUUM ANALYZE 清理死元组

必须引入的额外技术

但上面这些只是基础。以下三项,是我在经历过流量高峰后,认为必须引入的:

技术解决的痛点为什么"高并发"缺了它不行
Redis多实例缓存不一致、数据库被读请求打崩横向扩展后,每个实例的本地缓存彼此独立,会导致数据混乱。Redis 提供统一的缓存层,所有实例共享一份缓存。
消息队列 (如 BullMQ)高耗时任务阻塞 HTTP 线程、尖峰流量压垮系统当并发超出数据库处理能力时,新请求直接拒绝或排队。队列能将突发请求削峰填谷,让后端按节奏处理。
读写分离 (如 Pgpool-II)数据库单点读写瓶颈将查询操作分流到只读从库(Replica),写操作留在主库。

Redis:不只是缓存

在我目前的项目里,Redis 承担了三件事:

  1. 全栈缓存 —— 把 Next.js 的渲染结果或 API 响应缓存在 Redis 中,直接绕过数据库
  2. 会话共享 —— 用户登录状态统一存 Redis,多实例之间共享
  3. 队列后端 —— 配合 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

写在最后

高并发架构的演进是逐步的,不要试图一次性引入所有技术。先解决最痛的点,再不断完善。

我在实际踩坑中发现,很多时候系统的瓶颈并不在代码本身,而是在架构层面的缺失。希望这套组合拳能帮到你。