1️⃣ 适用场景与前置条件
优化前,请先确认你的环境是否符合以下要求,这是配置生效的基础。
| 项目 |
要求 |
| 适用场景 |
日均 PV 100万+ 的高并发 Web 应用,需要支持百万级连接 |
| OS 版本 |
RHEL/CentOS 8.0+ 或 Ubuntu 20.04 LTS+ |
| 内核版本 |
Linux Kernel 4.15+ (推荐 5.10+,支持 BBR) |
| Nginx 版本 |
1.20.x+ 或 1.24.x+(LTS 版本) |
| 资源规格 |
8C16G(最小)/ 16C32G(推荐)/ 32C64G(超大规模) |
| 网络 |
10Gbps+ 网络、万级连接数支持网卡 |
| 存储 |
SSD(日志 I/O 不能是瓶颈) |
| 权限 |
root 权限或能修改 /etc/nginx/ 目录 |
| 技能水平 |
高级运维工程师,理解 TCP/IP、HTTP 协议、性能优化 |
2️⃣ 反模式警告:哪些场景不适用?
⚠️ 以下场景不推荐使用此配置方案:
-
低并发、低流量应用
- 症状:日均 PV < 10万,应用响应时间 < 100ms
- 原因:百万级配置会浪费资源,反而增加复杂度
- 改进:使用 Nginx 官方默认配置即可
-
无监控、无告警系统
- 症状:调参后无法量化效果,性能衰减无法及时发现
- 改进:部署 Prometheus + Grafana 等监控后再调参
-
在生产高峰期直接修改参数
- 症状:调参失败导致业务中断、连接数暴涨
- 改进:参数变更在低峰期进行,且需 30 分钟观察期
-
盲目增大所有参数(如内存)
- 症状:worker_processes 设置 > CPU 核数,导致上下文切换频繁
- 改进:每个参数都有最优值,非“越大越好”
-
配置与 OpenResty/tengine 等分支混用
- 症状:配置语法差异导致启动失败
- 改进:本方案仅适用于原生 Nginx 1.20+
替代方案对比:
| 场景 |
推荐方案 |
理由 |
| 已有 CDN/LB |
仅优化源站 Nginx |
减少网络往返,性价比高 |
| API 网关场景 |
Kong/Traefik + Nginx |
Kong 提供更强的插件系统 |
| 实时性要求高 |
HAProxy + Nginx |
HAProxy 更快(C 语言实现) |
| 需要 Lua 动态脚本 |
OpenResty |
基于 Nginx + Lua 的强大组合 |
3️⃣ 快速清单(20分钟上手)
- [ ] 环境准备(5分钟)
- [ ] 确认 Nginx 版本 >= 1.20:
nginx -v
- [ ] 确认内核支持百万连接:
ulimit -n(需 >= 100万)
- [ ] 备份原始配置:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
- [ ] 应用优化配置(10分钟)
- [ ] 复制本方案的 nginx.conf 到
/etc/nginx/
- [ ] 修改 worker_processes、worker_connections 等关键参数
- [ ] 验证配置语法:
nginx -t
- [ ] 系统参数调优(10分钟)
- [ ] 编辑
/etc/sysctl.conf,应用网络优化参数
- [ ] 执行
sysctl -p 使生效
- [ ] 编辑
/etc/security/limits.conf,提升文件描述符上限
- [ ] 启动 & 验证(5分钟)
- [ ] 启动 Nginx:
systemctl restart nginx
- [ ] 检查进程:
ps aux | grep nginx
- [ ] 验证监听:
netstat -tln | grep 80
- [ ] 性能测试(30分钟)
- [ ] 用 Apache Bench 或 wrk 压测
- [ ] 观察 CPU、内存、网络占用
- [ ] 若能达到 10万+ RPS,则配置成功
4️⃣ 实施步骤详解:从系统到应用的全面优化
Step 1:系统级优化 - 突破百万连接上限
目标:让 Linux 内核支持百万级并发连接。
第 1 步:检查当前限制
# 查看全局文件描述符限制
cat /proc/sys/fs/file-max
# 预期输出:需要 >= 1000万(支持 100万 连接 x 10 倍安全系数)
# 查看进程级限制
ulimit -n
# 预期输出:通常 1024(太小!)
# 查看网络连接上限
cat /proc/sys/net/ipv4/ip_local_port_range
# 预期输出:32768 - 60999(共 ~28k 端口,这是基础)
# 查看 TCP TIME_WAIT 状态数
netstat -an | grep TIME_WAIT | wc -l
第 2 步:编辑系统配置文件
# 编辑 /etc/sysctl.conf
cat >> /etc/sysctl.conf << 'EOF'
### ===== 文件描述符相关 =====
fs.file-max = 10000000 # 全局最大 FD 数
### ===== TCP 连接相关 =====
# 监听队列
net.core.somaxconn = 65535 # listen 队列最大长度
net.ipv4.tcp_max_syn_backlog = 65535 # SYN 队列最大长度
# 连接复用(加快新连接建立)
net.ipv4.tcp_tw_reuse = 1 # 复用 TIME_WAIT 连接
net.ipv4.tcp_timestamps = 1 # 启用 TCP 时间戳(必须)
# 连接超时
net.ipv4.tcp_fin_timeout = 10 # FIN_WAIT2 超时(默认 60s,改为 10s)
net.ipv4.tcp_keepalive_time = 600 # keepalive 探测时间间隔(10 分钟)
net.ipv4.tcp_keepalive_probes = 3 # keepalive 探测次数
net.ipv4.tcp_keepalive_intvl = 15 # keepalive 探测间隔
# 缓冲区优化
net.core.rmem_default = 134217728 # 默认接收缓冲 128MB
net.core.rmem_max = 134217728 # 最大接收缓冲 128MB
net.core.wmem_default = 134217728 # 默认发送缓冲 128MB
net.core.wmem_max = 134217728 # 最大发送缓冲 128MB
net.ipv4.tcp_rmem = 4096 87380 134217728 # TCP 接收缓冲自动调整
net.ipv4.tcp_wmem = 4096 65536 134217728 # TCP 发送缓冲自动调整
# 网络设备队列
net.core.netdev_max_backlog = 100000 # 网卡接收队列最大长度
# 连接优化
net.ipv4.ip_local_port_range = 1024 65535 # 本地端口范围(默认 32768-60999)
net.ipv4.tcp_tw_recycle = 0 # 关闭 TIME_WAIT 快速回收(可能导致丢包)
# 性能优化
net.core.busy_read = 50 # 忙轮询(仅在超高性能场景)
net.core.busy_poll = 50
EOF
# 生效配置
sysctl -p
验证配置生效:
# 验证全局 FD 限制
cat /proc/sys/fs/file-max
# 预期输出:10000000
# 验证 listen 队列
cat /proc/sys/net/core/somaxconn
# 预期输出:65535
# 验证 TCP 缓冲
cat /proc/sys/net/core/rmem_max
# 预期输出:134217728
第 3 步:编辑进程级限制
# 编辑 /etc/security/limits.conf
cat >> /etc/security/limits.conf << 'EOF'
# Nginx 进程文件描述符限制
nginx soft nofile 1000000
nginx hard nofile 1000000
nginx soft nproc 1000000
nginx hard nproc 1000000
# 若以 root 启动(不推荐)
* soft nofile 1000000
* hard nofile 1000000
* soft nproc 1000000
* hard nproc 1000000
EOF
# 使生效(需要重新登录或重启 Nginx)
验证生效:
# 重启 Nginx 后检查
ps aux | grep nginx | head -1 | awk '{print $1}' > /tmp/nginx_user
cat /proc/$(pgrep -f 'nginx: worker' | head -1)/limits | grep "Max open files"
# 预期输出:Max open files 应该 >= 1000000
常见错误与解决:
- 错误 1:sysctl -p 提示某些参数不存在
# 症状
sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory
# 原因:内核版本太旧或参数被移除
# 解决:删除该参数,继续应用其他参数
sed -i '/tcp_tw_recycle/d' /etc/sysctl.conf
sysctl -p
- 错误 2:Nginx 进程级 FD 限制仍然是 1024
# 症状:ps 中看到 Nginx FD 限制仍为 1024
# 原因:limits.conf 修改后需要重启 Nginx
systemctl restart nginx
# 再验证
ps aux | grep nginx | head -1 | awk '{print $1}' | xargs cat /proc/$(pgrep -f 'nginx: worker' | head -1)/limits
回滚要点:
若调优后网络异常,恢复 /etc/sysctl.conf.bak:
cp /etc/sysctl.conf.bak /etc/sysctl.conf
sysctl -p
Step 2:Nginx 核心配置优化
目标:配置 Nginx 使其能高效处理百万级连接。以下是经过验证的核心配置模板。
配置模板 (/etc/nginx/nginx.conf):
# Nginx 百万级配置模板 v1.0
# 适用于:日均 PV 1000万+、并发连接 100万+ 的生产环境
#============ 全局块 ============
# 运行用户(不推荐用 root)
user nginx nginx;
# worker 进程数(通常 = CPU 核数)
# 查看:nproc 或 cat /proc/cpuinfo | grep processor | wc -l
# 设置规则:
# - CPU <= 8 核:worker_processes = CPU 核数
# - CPU > 8 核:worker_processes = CPU 核数 - 2(留资源给系统)
# - 或使用 auto(Nginx 自动检测)
worker_processes auto;
# worker 优先级(越小越优先,范围 -20 到 19)
worker_priority -10; # 提升 Nginx 优先级,让系统进程让步
# 错误日志
error_log /var/log/nginx/error.log warn;
# PID 文件
pid /var/run/nginx.pid;
# worker rlimit
worker_rlimit_nofile 1000000; # 每个 worker 最大 FD 数
worker_rlimit_core 0; # 关闭 core dump(节省磁盘)
#============ 事件块 ============
events {
# 每个 worker 最大并发连接数
# 规则:(系统最大 FD 数) / worker_processes
# 例如:1000000 / 16 = 62500,可安全设置 65536
worker_connections 65536;
# 事件模型(Linux 必须用 epoll)
use epoll;
# 是否一次调用 accept() 接受多个连接
multi_accept on;
# 优化:当 accept 队列有连接时立即处理
accept_mutex off; # 关闭互斥锁,提升并发处理能力
}
#============ HTTP 块 ============
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# ===== 日志配置 =====
# 日志格式(包含关键性能指标)
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
# 访问日志(高并发下建议关闭或用 buffer)
# 选项 1:完全关闭(最快,但无日志)
# access_log off;
# 选项 2:使用 buffer(推荐,平衡性能和可观测性)
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
# ===== 性能优化 =====
# 文件发送优化
sendfile on; # 启用 sendfile(零拷贝)
tcp_nopush on; # 禁用 Nagle 算法,加速小包发送
tcp_nodelay on; # 立即发送数据(HTTP 长连接需要)
# 超时配置
keepalive_timeout 65 65; # HTTP Keep-Alive 超时(推荐 60-120 秒)
client_body_timeout 10; # 客户端请求体读取超时
client_header_timeout 10; # 客户端请求头读取超时
send_timeout 10; # 发送响应超时
# 请求大小限制
client_max_body_size 20m; # 最大请求体大小(根据业务调整)
# 缓冲区优化
client_body_buffer_size 128k; # 请求体缓冲
client_header_buffer_size 1k; # 请求头缓冲
large_client_header_buffers 4 8k; # 大请求头缓冲
# Gzip 压缩(可选,CPU 密集但节省带宽)
gzip on;
gzip_vary on;
gzip_min_length 1k; # 小于 1KB 不压缩
gzip_comp_level 3; # 压缩级别 1-9(3 是性能和压缩的平衡)
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss;
gzip_disable "msie6"; # 禁用 IE6 gzip
# HTTP 版本
http2_max_field_size 16k; # HTTP/2 字段大小限制
http2_max_header_size 32k;
# 哈希表优化(减少哈希冲突)
types_hash_max_size 2048;
variables_hash_max_size 1024;
variables_hash_bucket_size 128;
server_names_hash_max_size 1024;
server_names_hash_bucket_size 128;
# 连接池优化(后端连接复用)
upstream_keepalive_connections 64; # 保持最多 64 个连接到后端
upstream_keepalive_timeout 60; # 后端连接空闲超时
upstream_keepalive_requests 100; # 单条连接最多处理 100 个请求
# ===== 代理优化 =====
# (若 Nginx 作为反向代理时)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_redirect off;
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;
proxy_connect_timeout 5s; # 连接超时
proxy_send_timeout 10s; # 发送超时
proxy_read_timeout 10s; # 读取超时
# ===== 限流 & 安全 =====
# 限制并发连接数(防止某个 IP 占用过多连接)
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10; # 每个 IP 最多 10 个并发连接
# 限制请求速率(防止暴力请求)
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_req zone=req_limit burst=20 nodelay;
#============ Server 块(虚拟主机)============
# 健康检查端点(内部使用,不记录日志)
server {
listen 8080;
server_name _;
location /health {
access_log off;
return 200 "ok\n";
add_header Content-Type text/plain;
}
location /metrics {
access_log off;
return 200 "Nginx metrics endpoint\n";
add_header Content-Type text/plain;
}
}
# 主服务(Web 应用)
server {
listen 80 deferred reuseport backlog=65535;
# listen [::]:80 deferred reuseport backlog=65535; # IPv6(可选)
server_name _;
# SSL(可选,若需 HTTPS)
# listen 443 ssl http2 deferred reuseport backlog=65535;
# ssl_certificate /etc/nginx/ssl/cert.pem;
# ssl_certificate_key /etc/nginx/ssl/key.pem;
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
# ssl_session_tickets off;
# ssl_stapling on;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 根路径
root /var/www/html;
index index.html index.htm;
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 动态请求代理到后端
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_connection_manager true;
proxy_buffering on;
}
# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# 后端应用服务器定义
upstream backend {
# 保持连接复用
keepalive 64;
# 后端服务器列表
server 192.168.1.10:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.1.11:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.1.12:8080 weight=1 max_fails=2 fail_timeout=10s;
# 负载均衡算法(默认轮询)
# least_conn; # 最少连接
# ip_hash; # 基于 IP 哈希(会话保持)
# hash $uri; # 基于 URI 哈希
}
}
关键参数详解:
worker_processes
- 最优值:CPU 核数(多了反而降速,因为上下文切换)
- 查看命令:
nproc 或 cat /proc/cpuinfo | grep processor | wc -l
worker_connections
- 最优值:
(系统最大 FD 数 - 预留) / worker_processes
- 例如:(100万 - 10万) / 16 = 5.6万,可设 65536
listen backlog
- 含义:等待 accept() 的连接队列深度
- 最优值:与
net.core.somaxconn 一致(65535)
keepalive_timeout
- 含义:HTTP Keep-Alive 连接保活时间
- 推荐:60-120 秒(太小频繁断连,太大积压僵尸连接)
proxy_buffering
on:Nginx 缓冲后端响应(适合后端慢)
off:流式发送,延迟低(适合后端快)
验证配置语法:
nginx -t
# 预期输出:语法 OK
常见错误与解决:
Step 3:性能测试与验证
目标:验证配置是否达到百万级处理能力。
安装测试工具:
- RHEL/CentOS:
yum install -y httpd-tools 或 yum install -y wrk
- Ubuntu/Debian:
apt install -y apache2-utils 或 apt install -y wrk
基准测试 1:Apache Bench 压测
# 发起 100 万个请求,并发 1000
ab -n 1000000 -c 1000 http://localhost/
# 关键指标解释:
# - Requests per second: 吞吐量(RPS),> 100K 说明配置成功
# - Time per request:平均延迟,< 100ms 为优秀
# - Failed requests:失败次数,应该为 0
基准测试 2:复杂场景的 wrk 压测
# 用 wrk 模拟更复杂的场景:10 个线程,1000 并发连接,持续 30 秒
wrk -t10 -c1000 -d30s http://localhost/
# 关键指标:
# - Latency:响应延迟(Avg < 50ms,p99 < 200ms 为好)
# - Req/Sec:每秒吞吐量
5️⃣ 核心原理:为什么 Nginx 能处理百万连接?
Nginx 的强大源于其事件驱动、异步非阻塞的架构。它与传统的每个连接一个线程(或进程)的模型截然不同。
关键机制:
- 异步非阻塞 I/O (epoll): 每个 worker 进程使用一个线程,通过 epoll 监控所有连接。只有连接上有数据可读/写时,worker 才去处理,避免了为大量空闲连接创建线程的开销。
- 内存开销小: 每个空闲连接主要占用 socket buffer 和少量元数据(约10-30KB)。100万连接的理论内存占用约为20-30GB,在现代服务器上是可接受的。
- CPU 开销集中在活跃连接: 大多数连接处于空闲状态,不消耗CPU。CPU只处理实际有数据交互的活跃连接(通常只占总连接的1-10%)。
关键参数的性能影响:
| 参数 |
值 |
性能影响 |
说明 |
worker_processes |
CPU 核数 |
最优吞吐 |
多于 CPU 核数会因上下文切换降速 |
worker_connections |
65536 |
连接容量 |
受系统 FD 限制,决定单worker最大连接数 |
worker_priority |
-10 |
CPU 分配 |
优先级高,让系统进程让步,响应更快 |
keepalive_timeout |
60 |
连接复用 |
平衡连接复用效率和僵尸连接数量 |
tcp_nopush + sendfile |
on |
吞吐量/CPU |
减少网络包数并启用零拷贝,大幅提升静态文件发送效率 |
6️⃣ 监控、告警与故障排查
没有监控的优化是盲目的。部署完成后,必须建立可观测性体系。
启用 Nginx 原生状态监控:
在配置文件的 server 块中添加:
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1; # 限制访问IP
deny all;
}
访问 http://your-server:port/nginx_status 可看到关键指标:活跃连接数(Active connections)、总处理请求数、读/写/等待状态的连接数。
健康的百万级 Nginx 基准指标:
- 吞吐量:> 100K RPS(单机 16C32G)
- 延迟:p50 < 10ms, p95 < 50ms, p99 < 200ms
- 连接数:可稳定维持 > 50万 ESTABLISHED 连接
- 资源:CPU < 80%,内存 < 90%,错误率 < 0.01%
常见问题快速排错表:
| 症状 |
诊断命令 |
可能根因 |
快速修复 |
| RPS 瓶颈在 10-20K |
top 看 CPU |
worker太少或CPU受限 |
增加 worker_processes 或升级硬件 |
| 大量 TIME_WAIT 连接 |
netstat -an \| grep TIME_WAIT \| wc -l |
后端慢或请求频繁 |
启用 tcp_tw_reuse (见Step1) |
| 502 Bad Gateway |
tail /var/log/nginx/error.log |
后端宕机或连接耗尽 |
检查后端服务,增加 upstream keepalive |
| 内存持续增长 |
free -h 监控1小时 |
内存泄漏 |
升级 Nginx 版本或检查第三方模块 |
| 请求延迟高 |
wrk -t10 -c1000 -d30s 测试 |
后端处理慢或网络问题 |
优化后端应用,检查网络链路 |
7️⃣ 最佳实践与 FAQ
最佳实践:
- 保留20%余量:CPU、内存、连接数使用率最好都控制在80%以下,以应对突发流量。
- 定期压测建立基线:每月用 wrk 等工具进行压测,对比历史数据,提前发现性能衰减。
- 自动化部署:使用 Ansible/Terraform 等工具部署配置,减少人工错误,方便回滚。
- 分析慢请求日志:定期分析
access.log 中响应时间过长的请求(如 >100ms),定位上游瓶颈。
FAQ:
- Q1:真能达到100万连接吗?
A:可以。早期限制源于默认配置(worker_connections=512)。现代方案通过提升系统FD上限、优化内核参数、合理配置Nginx(如16 workers × 6.25万连接),百万连接是理论可达的稳定目标。
- Q2:100万连接占用多少内存?
A:约20-30GB。主要取决于每个连接的缓冲区大小(net.core.rmem/wmem)。大部分是空闲连接的 socket buffer 开销。
- Q3:后端处理不过来怎么办?
A:利用 Nginx 的缓冲和队列能力。设置 proxy_buffering on; 让 Nginx 先缓冲响应。同时,在 upstream 中合理设置 keepalive 和 max_fails 对后端进行限流和保护。
- Q4:能用 Nginx 完全替代硬件负载均衡器(LB)吗?
A:在负载均衡功能上可以,但高可用(HA)需要额外组件(如 Keepalived 实现 VIP 漂移)。对于大规模生产环境,更推荐 “云LB → Nginx 集群 → 后端” 的分层架构,让专业LB做流量分发和高可用,Nginx专注于业务流量处理和应用层优化。
通过以上从系统内核、Nginx配置、压力测试到监控告警的全套优化方案,你可以构建出能够应对百万级并发的高性能 Web 服务前端。记住,调优是一个持续的过程,需要结合实际的监控数据不断迭代。如果在实践中遇到更多具体问题,欢迎在技术社区进行深度交流,例如在 云栈社区 的相关板块与同行们一起探讨。