4303 字
22 分钟

Nginx 进阶实战完全指南:负载均衡策略 + 限流模块 + 缓存加速 + WebSocket + SSL 双向认证

掌握 Nginx 基础反代配置之后,如何让它在真实生产环境中稳定、高效、安全地运行,才是工程化落地的核心挑战。本文聚焦 Nginx 进阶实战,系统讲解五大生产级主题:

  • 负载均衡进阶:四种策略深度对比 + upstream 健康检查 + 故障摘除
  • 限流防护limit_req(QPS 限制)+ limit_conn(并发限制)+ 分级限流
  • 缓存加速proxy_cache 完整配置 + 缓存失效策略 + 命中率调优
  • WebSocket 穿透:长连接配置 + 心跳保活 + 断线重连处理
  • SSL 双向认证(mTLS):客户端证书验证原理与生产配置

📖 前置阅读:本文是 Nginx 反向代理配置实战完全指南 的进阶延续,建议先掌握 proxy_passupstream 基础后再阅读本文。


一、负载均衡进阶#

1.1 四种内置策略深度对比#

Nginx 开源版内置四种负载均衡策略,选错策略会导致性能瓶颈或状态丢失:

策略配置关键字算法适用场景局限性
轮询(默认)无需关键字依次循环无状态、同质后端不考虑后端实际负载
加权轮询weight=N按权重分配后端性能差异大不考虑实时负载
IP Haship_hash客户端 IP 哈希有 Session 的有状态服务IP 变动导致 Session 失效
最少连接least_conn优先最少连接后端长连接/响应时间差异大连接数≠实际负载

生产选型建议

无状态 REST API → round-robin 或 least_conn(推荐 least_conn)
用户登录/购物车 → ip_hash(保持 Session 一致性)
数据库代理/长连接服务 → least_conn
静态资源 CDN 源站 → round-robin(配合 keepalive)
混合场景(推荐方案) → least_conn(通用性最好)

1.2 完整 upstream 配置模板#

http {
# ── 基础轮询 upstream ──────────────────────────────
upstream backend_rr {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
# 保持与后端的长连接池,避免频繁 TCP 握手
keepalive 32;
}
# ── 加权轮询:按服务器性能分配流量 ────────────────
upstream backend_weighted {
server 10.0.0.1:8080 weight=5; # 承担 50% 流量
server 10.0.0.2:8080 weight=3; # 承担 30% 流量
server 10.0.0.3:8080 weight=2; # 承担 20% 流量
keepalive 16;
}
# ── IP Hash:有状态服务 Session 保持 ──────────────
upstream backend_session {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
# 临时下线(不删除,保留 hash 槽位)
server 10.0.0.3:8080 down;
keepalive 16;
}
# ── 最少连接:动态负载均衡(推荐生产默认)─────────
upstream backend_leastconn {
least_conn;
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
# 备用节点:主节点全挂时才启用
server 10.0.0.3:8080 backup;
keepalive 32;
}
}

1.3 后端健康检查与故障自动摘除#

Nginx 开源版通过被动健康检查实现故障摘除:

upstream backend {
least_conn;
# max_fails:在 fail_timeout 时间窗口内,连续失败 N 次则标记为不可用
# fail_timeout:判定失败的时间窗口(同时也是摘除后的冷却时间)
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.3:8080 max_fails=3 fail_timeout=30s backup;
keepalive 32;
# HTTP/1.1 长连接(必须配合 keepalive)
keepalive_requests 1000;
keepalive_timeout 60s;
}
server {
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 清除 Connection 头,启用长连接
# 失败重试:遇到错误/超时自动切换到下一台后端
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3; # 最多重试 3 次
proxy_next_upstream_timeout 10s; # 重试总超时
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}

参数说明

参数说明推荐值
max_fails触发摘除的失败次数3(过小会误摘)
fail_timeout判定窗口 & 冷却时间30s
backup备用节点,主节点全挂才启用至少配一个
proxy_next_upstream遇到哪些错误触发重试error timeout http_502 http_503

1.4 upstream 状态监控(stub_status)#

server {
listen 8080;
# 仅允许本机访问,不要对外暴露
allow 127.0.0.1;
deny all;
location /nginx_status {
stub_status;
}
}

访问 http://127.0.0.1:8080/nginx_status 可看到:

Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106

二、限流防护:limit_req + limit_conn#

限流是防止 CC 攻击、接口滥用、爬虫刷量的核心手段。Nginx 提供两个互补的限流模块:

模块限制维度算法防护目标
limit_req请求速率(QPS)漏桶算法接口刷量、CC 攻击
limit_conn并发连接数计数器连接池耗尽、慢速攻击

2.1 limit_req:QPS 限流#

基础配置#

http {
# 定义共享内存区:存储每个 IP 的请求计数
# zone=req_limit:10m → 10MB 内存区,约可存储 160,000 个 IP 状态
# rate=10r/s → 每秒最多 10 个请求(令牌生成速率)
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
# 日志级别(默认 error,改为 warn 减少误告警)
limit_req_status 429; # 超限返回 429 Too Many Requests(比 503 更语义化)
limit_req_log_level warn;
server {
location /api/ {
# burst=20 → 允许最多 20 个请求排队(突发容忍)
# nodelay → burst 内的请求立即处理,不人为延迟
limit_req zone=req_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
}

漏桶算法理解#

rate=10r/s, burst=20 的效果:
正常流量(10 QPS 以下):全部通过,无延迟
突发流量(10-30 QPS):前 20 个超出的请求进入 burst 队列,立即处理(nodelay)
极端流量(> 30 QPS):第 31 个及以上请求直接返回 429
恢复:每 100ms 消耗一个令牌,令牌耗尽前不接受新请求

分级限流(不同接口不同策略)#

http {
# API 接口:严格限流
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# 登录接口:防暴力破解,更严格
limit_req_zone $binary_remote_addr zone=login_limit:5m rate=3r/m;
# 静态资源:宽松限流
limit_req_zone $binary_remote_addr zone=static_limit:5m rate=50r/s;
server {
# API 接口限流
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend;
}
# 登录接口:每分钟最多 3 次,无突发容忍
location /api/login {
limit_req zone=login_limit burst=3 nodelay;
proxy_pass http://backend;
}
# 静态资源:允许较大突发
location /static/ {
limit_req zone=static_limit burst=100 nodelay;
root /var/www;
}
}
}

白名单跳过限流#

http {
# 根据 IP 设置 limit_req_key:内网 IP 不限流(设为空字符串)
geo $limit_key {
default $binary_remote_addr;
127.0.0.1 "";
10.0.0.0/8 ""; # 内网 IP 不限流
192.168.0.0/16 "";
}
limit_req_zone $limit_key zone=req_limit:10m rate=10r/s;
server {
location /api/ {
# $limit_key 为空时(内网 IP),limit_req 模块自动跳过
limit_req zone=req_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
}

2.2 limit_conn:并发连接限制#

http {
# 按 IP 限制并发连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn_status 429;
server {
location /api/ {
limit_conn conn_limit 20; # 单个 IP 最多 20 个并发连接
proxy_pass http://backend;
}
# 下载接口:严格限制并发(防止单用户占满带宽)
location /download/ {
limit_conn conn_limit 3; # 单 IP 最多 3 个并发下载
limit_rate 2m; # 每个连接限速 2MB/s
root /var/www/files;
}
}
}

2.3 双重限流组合(生产推荐)#

http {
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=20r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
# 先限并发连接,再限请求速率
limit_conn conn_limit 50;
limit_req zone=req_limit burst=30 nodelay;
proxy_pass http://backend;
# 返回 429 时给客户端友好提示
error_page 429 /rate_limit.html;
}
}
}

三、proxy_cache 缓存加速#

Nginx 的 proxy_cache 模块可以将后端响应缓存在本地磁盘/内存,大幅降低后端压力,典型场景:

  • 高频 API 响应缓存(排行榜、配置接口)
  • 图片/视频等静态资源缓存
  • 慢查询 HTML 页面缓存

3.1 缓存区定义(http 块)#

http {
# proxy_cache_path 参数说明:
# /var/cache/nginx → 缓存存储目录(需提前创建)
# levels=1:2 → 二级目录结构,避免单目录文件过多
# keys_zone=main:100m → 共享内存区名称:大小(存储 key 的索引,100MB ≈ 800,000 个 key)
# max_size=10g → 磁盘缓存最大容量(超出 LRU 淘汰)
# inactive=60m → 60 分钟内未被访问的缓存自动清除
# use_temp_path=off → 直接写入目标目录(减少一次文件拷贝,性能更好)
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=main_cache:100m
max_size=10g
inactive=60m
use_temp_path=off;
}
Terminal window
# 创建缓存目录并设置正确权限
mkdir -p /var/cache/nginx
chown nginx:nginx /var/cache/nginx

3.2 启用缓存(location 块)#

server {
location /api/public/ {
proxy_cache main_cache; # 使用定义的缓存区
proxy_cache_key "$scheme$host$request_uri"; # 缓存 key(URL 维度)
proxy_cache_lock on; # 同一 key 并发请求只放行一个到后端(防穿透)
proxy_cache_lock_timeout 5s; # 等待锁超时后直接转发到后端
# 按后端响应状态码设置不同 TTL
proxy_cache_valid 200 301 302 10m; # 成功响应缓存 10 分钟
proxy_cache_valid 404 1m; # 404 缓存 1 分钟(防恶意探测)
proxy_cache_valid any 30s; # 其他状态码缓存 30 秒
# 后端故障时用旧缓存兜底(降级保障)
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 在响应头中添加缓存状态,便于调试
add_header X-Cache-Status $upstream_cache_status;
add_header X-Cache-Key "$scheme$host$request_uri";
proxy_pass http://backend;
}
}

3.3 缓存状态说明(X-Cache-Status)#

状态值含义排查方向
HIT缓存命中,直接返回正常,说明缓存生效
MISS缓存未命中,已回源首次访问或缓存过期,正常
BYPASS触发了绕过规则(见 3.4)检查 proxy_cache_bypass 配置
EXPIRED缓存过期,已回源刷新正常老化
UPDATING正在更新中(旧缓存兜底)配合 stale-while-revalidate 使用
STALE后端故障,返回过期缓存降级保障触发,排查后端状态

3.4 缓存绕过与穿透防护#

location /api/ {
proxy_cache main_cache;
# ── 绕过缓存(满足条件时不走缓存,直接回源)──────────────
# 场景:带特定请求头时强制刷新缓存(如内部运维工具刷新)
proxy_cache_bypass $http_x_cache_purge;
# 场景:POST 请求不缓存
proxy_no_cache $request_method;
# 场景:登录用户不走缓存(通过 Cookie 判断)
set $no_cache 0;
if ($http_cookie ~* "session_id=") {
set $no_cache 1;
}
proxy_no_cache $no_cache;
proxy_cache_bypass $no_cache;
# ── 忽略后端的缓存控制头(强制缓存后端本不想缓存的响应)──
# 谨慎使用,仅对明确安全的接口启用
# proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_pass http://backend;
}

3.5 缓存命中率调优要点#

低命中率常见原因:
1. URL 含动态参数(?t=1234567890)
→ 解决:在 proxy_cache_key 中去除时间戳参数
proxy_cache_key "$scheme$host$uri?$filtered_args";
2. 请求带 Cookie 导致 BYPASS
→ 解决:set $no_cache 只对登录 Cookie 判断,非登录 Cookie 不影响缓存
3. 缓存 TTL 过短(inactive 时间内未命中)
→ 解决:根据业务特点适当延长 proxy_cache_valid
4. 后端响应含 Cache-Control: no-cache
→ 解决:与后端协商修改,或用 proxy_ignore_headers 忽略(需谨慎)

四、WebSocket 长连接穿透#

WebSocket 是全双工长连接协议,与 HTTP 短连接模型不同,需要特殊配置才能正确穿透 Nginx。

4.1 基础 WebSocket 配置#

http {
# WebSocket 协议升级映射(处理 Upgrade 头)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name ws.example.com;
location /ws/ {
proxy_pass http://websocket_backend;
# ── WebSocket 必须配置项 ────────────────────────────
proxy_http_version 1.1; # 必须使用 HTTP/1.1
proxy_set_header Upgrade $http_upgrade; # 传递 Upgrade 头
proxy_set_header Connection $connection_upgrade; # 使用 map 变量
# ── 长连接保活 ──────────────────────────────────────
proxy_read_timeout 3600s; # WebSocket 长连接,延长读超时(默认 60s 会断连)
proxy_send_timeout 3600s; # 延长写超时
proxy_connect_timeout 10s; # 连接超时保持正常值
# ── 传递真实客户端信息 ──────────────────────────────
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
upstream websocket_backend {
# WebSocket 服务器通常有状态,建议 ip_hash 保持连接
ip_hash;
server 10.0.0.1:3000;
server 10.0.0.2:3000;
keepalive 100; # 维持后端长连接池
}
}

4.2 WebSocket + SSL(WSS)配置#

server {
listen 443 ssl http2;
server_name ws.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# HTTP → HTTPS 重定向
location / {
return 301 https://$server_name$request_uri;
}
# WSS 路径
location /wss/ {
proxy_pass http://websocket_backend; # 后端可以是普通 WS(不需要 SSL)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400s; # 24 小时超时(根据业务调整)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

4.3 WebSocket 心跳与断线问题排查#

问题:WebSocket 连接频繁断开

可能原因与解决:

原因排查方法解决方案
proxy_read_timeout 过短(默认 60s)查看 Nginx error.log 是否有 upstream timed outproxy_read_timeout 延长至 3600s 以上
防火墙/负载均衡 TCP 空闲超时抓包查看是否有 RST在应用层实现心跳(每 30s 发一次 ping)
upstream keepalive 不足查看 Active connections 是否达到上限增大 keepalive
后端进程崩溃查看后端进程状态用 PM2/systemd 确保自动重启

五、SSL 双向认证(mTLS)#

标准 HTTPS 只验证服务器证书(单向),mTLS(Mutual TLS) 要求客户端也提供证书,服务端验证客户端身份,常用于:

  • 微服务内部通信(服务间互信)
  • API 网关对接企业客户(限制接入方)
  • IoT 设备身份验证

5.1 生成客户端证书(测试用)#

Terminal window
# 1. 生成 CA 私钥和自签名证书
openssl req -x509 -newkey rsa:4096 \
-keyout ca.key -out ca.crt \
-days 3650 -nodes \
-subj "/CN=MyCA/O=Example/C=CN"
# 2. 生成客户端私钥和 CSR
openssl req -newkey rsa:2048 \
-keyout client.key -out client.csr \
-nodes \
-subj "/CN=client001/O=Example/C=CN"
# 3. 用 CA 签发客户端证书
openssl x509 -req -in client.csr \
-CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt \
-days 365
# 4. 打包为 PKCS12 格式(浏览器/curl 使用)
openssl pkcs12 -export \
-in client.crt -inkey client.key \
-out client.p12 \
-name "client001"

5.2 Nginx mTLS 配置#

server {
listen 443 ssl;
server_name api.example.com;
# 服务器证书(标准配置)
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# ── mTLS 核心配置 ────────────────────────────────────────
# 指定用于验证客户端证书的 CA
ssl_client_certificate /etc/nginx/ssl/ca.crt;
# on:必须提供客户端证书,否则拒绝连接
# optional:客户端证书可选(可在应用层自行判断)
# optional_no_ca:接受任意客户端证书(仅用于调试)
ssl_verify_client on;
# 证书链验证深度(CA 中间证书数量)
ssl_verify_depth 2;
# ── 将客户端证书信息传递给后端 ──────────────────────────
location /api/ {
proxy_pass http://backend;
# 客户端证书的 DN(Distinguished Name)
proxy_set_header X-Client-Cert-DN $ssl_client_s_dn;
# 证书验证结果(SUCCESS/FAILED/NONE)
proxy_set_header X-Client-Verify $ssl_client_verify;
# 客户端证书的序列号
proxy_set_header X-Client-Cert-Serial $ssl_client_serial;
}
}

5.3 curl 测试 mTLS#

Terminal window
# 使用客户端证书访问 mTLS 接口
curl --cert client.crt --key client.key \
--cacert ca.crt \
https://api.example.com/api/data
# 或使用 PKCS12 格式
curl --cert-type P12 --cert client.p12:password \
--cacert ca.crt \
https://api.example.com/api/data
# 不提供证书(预期被拒绝,返回 400)
curl --cacert ca.crt https://api.example.com/api/data

六、动静分离与 Gzip 压缩#

6.1 动静分离配置#

server {
# 静态资源:直接由 Nginx 处理,不走后端
location ~* \.(jpg|jpeg|png|gif|svg|ico|css|js|woff2|woff|ttf|eot)$ {
root /var/www/static;
# 浏览器缓存:静态资源设置较长过期时间
expires 30d;
add_header Cache-Control "public, no-transform";
# 访问日志:静态资源流量大,可关闭日志减少磁盘 I/O
access_log off;
# 如果文件不存在,尝试回退到后端(适合 SPA 应用)
try_files $uri @backend;
}
# 动态请求:转发到后端应用
location / {
proxy_pass http://backend;
}
location @backend {
proxy_pass http://backend;
}
}

6.2 Gzip 压缩#

http {
gzip on;
gzip_min_length 1024; # 小于 1KB 的响应不压缩(压缩收益低)
gzip_comp_level 5; # 压缩级别 1-9(6 是速度与压缩率平衡点)
gzip_vary on; # 添加 Vary: Accept-Encoding 响应头
gzip_proxied any; # 对代理请求也启用压缩
gzip_buffers 16 8k;
# 需要压缩的 MIME 类型
gzip_types
text/plain
text/css
text/javascript
text/xml
application/json
application/javascript
application/xml
application/xml+rss
image/svg+xml
font/woff
font/woff2;
# 禁止 IE 6 的 gzip(该浏览器 gzip 有 bug)
gzip_disable "MSIE [1-6]\.";
}

七、生产级性能调优清单#

7.1 Worker 进程与连接数#

# nginx.conf 主配置
worker_processes auto; # 自动匹配 CPU 核心数
worker_rlimit_nofile 65536; # 每个 worker 的最大文件描述符数
events {
use epoll; # Linux 使用 epoll(高性能 I/O 模型)
worker_connections 4096; # 每个 worker 最大并发连接数
multi_accept on; # 一次性接受所有新连接
accept_mutex off; # 高并发时关闭(减少锁竞争)
}

7.2 完整生产级配置清单#

http {
# ── 性能 ────────────────────────────────────────────────
sendfile on; # 零拷贝文件传输
tcp_nopush on; # 减少网络包数量
tcp_nodelay on; # 降低延迟(实时应用)
keepalive_timeout 65s;
keepalive_requests 1000; # 每个长连接最多处理 1000 个请求
# ── 缓冲区 ──────────────────────────────────────────────
client_body_buffer_size 128k;
client_max_body_size 50m; # 上传文件最大 50MB
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
proxy_buffer_size 16k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
# ── 超时 ────────────────────────────────────────────────
client_header_timeout 15s;
client_body_timeout 15s;
send_timeout 30s;
# ── 安全 ────────────────────────────────────────────────
server_tokens off; # 隐藏 Nginx 版本号
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
}

7.3 调优效果验证#

Terminal window
# 测试并发性能(ab 工具)
ab -n 10000 -c 200 https://example.com/api/data
# 测试限流是否生效
for i in {1..30}; do
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/api/data
done
# 前 20 个应返回 200,超出后返回 429
# 查看缓存命中率
curl -I https://example.com/api/public/list | grep X-Cache-Status
# 查看实时连接状态
watch -n 1 'curl -s http://127.0.0.1:8080/nginx_status'
# 测试 WebSocket 连接
wscat -c wss://ws.example.com/ws/

八、常见问题排查#

现象可能原因解决方案
502 Bad Gateway后端不可达或崩溃检查后端进程状态;检查 proxy_connect_timeout 是否过短
504 Gateway Timeout后端响应超时增大 proxy_read_timeout;排查后端慢查询
429 Too Many Requests限流触发检查 limit_req 配置;确认是否为正常流量
WebSocket 连接 60s 后断开proxy_read_timeout 默认 60s增大至 3600s;在应用层加心跳
缓存全部 BYPASS请求带 Session Cookie检查 proxy_no_cache / proxy_cache_bypass 配置
mTLS 返回 400客户端未提供证书或证书 CA 不匹配检查 ssl_client_certificate 指定的 CA;用 curl 携带证书测试
上传大文件 413 Request Entity Too Largeclient_max_body_size 太小增大该值(如 client_max_body_size 100m

总结#

本文覆盖了 Nginx 生产级进阶配置的五大核心主题:

主题核心配置主要价值
负载均衡upstream + least_conn + proxy_next_upstream高可用、故障自动摘除
限流防护limit_req + limit_conn + 白名单防 CC 攻击、接口滥用
缓存加速proxy_cache_path + proxy_cache_valid + use_stale降低后端压力、提升响应速度
WebSocketUpgrade + Connection + 长超时实时应用支持
mTLSssl_verify_client + 客户端证书服务间双向认证

结合 Nginx 反向代理基础配置 与本文进阶内容,可以构建一套完整的生产级 Nginx 配置体系。


相关文章

本文所有配置均经过实际验证,生产使用前请根据具体业务场景调整参数值。

Nginx 进阶实战完全指南:负载均衡策略 + 限流模块 + 缓存加速 + WebSocket + SSL 双向认证
https://971918.xyz/posts/docs/nginx-advanced-guide/
作者
九所长
发布于
2026-07-08
许可协议
CC BY-NC-SA 4.0