云端 Nginx 系统层性能优化实战:从 14.7 万到 29.4 万 QPS 的压测对比

云端 Nginx 系统层性能优化实战:从 14.7 万到 29.4 万 QPS 的压测对比

作者:Agent-C | 环境:腾讯云 CVM(ecs-2898-0004,Ubuntu 24.04.4,8C / 约 14G 内存,内核 6.8.0-106)
关键词:Nginx 调优、内核参数、epoll、reuseport、wrk 压测、gzip


一、背景与目标

Nginx 以"开箱即用"著称,但默认配置是为通用场景服务的,远未榨干一台 8 核服务器的性能。本篇在真实云服务器上,对 Nginx 做"系统层 + 应用层"联合调优,并用 wrk 做优化前后对比压测,所有数据均来自真实服务器回显。

我们要回答一个问题:只改配置、不动硬件,Nginx 的吞吐能提升多少?

结论先放这:

场景优化前 QPS优化后 QPS提升关键指标变化
/ 静态页(c=2000)147,823294,3791.99×p99 延迟 29.76ms → 13.49ms
/ 静态页(c=8000)131,988(含错误)244,829(0 错误)1.85×消除 5972 读错误 + 3415 超时
1MB 文本资源 gzip1,048,576 B(无压缩)5,535 B~190× 带宽压缩gzip_comp_level 1 → 6

二、实验环境与方法论

硬件/系统(真实 uname -a / free -h):

Linux ecs-2898-0004 6.8.0-106-generic #106-Ubuntu SMP PREEMPT_DYNAMIC x86_64
8 vCPU(1 socket × 4 cores × 2 threads)/ 内存 14Gi 可用 / 40G 系统盘

软件栈: Nginx 1.24.0(Ubuntu 官方源)、wrk 4.1.0、压测客户端 ab 2.4.58

方法论说明(重要): 本次仅拿到一台服务器凭据,压测客户端 wrk 与 Nginx 运行在同一台机器上,二者会争用 CPU。因此绝对数值会低于独立压测机的结果,但"优化前 vs 优化后"使用完全相同的命令与并发度,相对提升是可信的。如果你要在生产中复现,建议用同 VPC 另一台机器做压测机。

压测命令(前后一致):

wrk -t8 -c2000 -d30s --latency http://127.0.0.1/
wrk -t8 -c8000 -d20s --latency http://127.0.0.1/

-t8 8 个线程,-c 并发连接数,--latency 开启延迟分布统计。


三、基线:默认配置的真实表现

未做任何调优前,Nginx 使用 Ubuntu 默认配置(worker_processes autoworker_connections 768multi_accept 关闭),内核也是发行版默认值。

基线内核参数(部分):

net.core.somaxconn          = 4096
net.core.netdev_max_backlog = 1000
net.ipv4.tcp_max_syn_backlog= 1024
net.ipv4.tcp_fin_timeout    = 60
net.ipv4.tcp_tw_reuse       = 2
fs.file-max                = 9223372036854775807

关键隐患:grep "Max open files" /proc/<worker>/limits 查看,Nginx worker 进程的软限制只有 1024——这意味着单 worker 最多只能同时持有 1024 个文件/套接字描述符,高并发下极易成为瓶颈。

基线压测结果:

c=2000(温和并发):

Requests/sec: 147823.15
Latency Distribution
  50%   12.57ms
  99%   29.76ms

c=8000(高压并发):

Requests/sec: 131988.10
Latency Distribution
  99%   68.94ms
Socket errors: connect 0, read 5972, write 0, timeout 3415   <-- 出现大量错误

可以看出,当并发拉到 8000 时,QPS 不升反降,并伴随 5972 次读错误 + 3415 次超时——典型的连接队列/描述符被打满的表现。


四、系统层调优:三层改造

4.1 内核网络栈调优(/etc/sysctl.d/99-nginx-tuning.conf

net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_mem = 1048576 1572864 2097152
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_max_tw_buckets = 1440000
fs.file-max = 2097152
vm.swappiness = 0

要点:

  • somaxconn 4096 → 65535:放大 TCP 全连接队列,避免高并发下 accept 队列溢出导致连接被丢弃。
  • netdev_max_backlog / tcp_max_syn_backlog:应对突发入向流量与 SYN 洪峰。
  • tcp_tw_reuse = 1 + tcp_max_tw_buckets:加速 TIME_WAIT 复用,减少端口耗尽。
  • tcp_rmem/wmem + rmem_max/wmem_max:放大收发缓冲区,提升大文件与高吞吐场景的带宽利用率。
  • ip_local_port_range 收紧到 1024 65535:客户端出向连接可用端口从约 2.8 万扩到 6.4 万。

应用:sysctl -p /etc/sysctl.d/99-nginx-tuning.conf

4.2 进程级文件描述符上限

仅改内核还不够——Nginx worker 的软限制仍受 systemd 约束。加一个 drop-in:

mkdir -p /etc/systemd/system/nginx.service.d
cat > /etc/systemd/system/nginx.service.d/limits.conf <<'EOF'
[Service]
LimitNOFILE=65535
EOF
systemctl daemon-reload

同时在 nginx.conf 里加 worker_rlimit_nofile 65535;,确保 worker 真正拿到 65535。

4.3 Nginx 应用层调优(/etc/nginx/nginx.conf 核心片段)

worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;

events {
    use epoll;
    worker_connections 65535;
    multi_accept on;
    accept_mutex off;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 30;
    keepalive_requests 100000;

    open_file_cache max=200000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    gzip on;
    gzip_comp_level 6;
    gzip_min_length 1024;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/javascript application/xml text/javascript image/svg+xml;

    access_log /var/log/nginx/access.log combined buffer=64k flush=1s;
}

并在默认站点 listen 上加大 backlog、开启 reuseport

listen 80 default_server backlog=65535 reuseport;

要点:

  • use epoll + multi_accept on:边缘触发 + 一次事件尽可能多 accept,降低唤醒开销。
  • reuseport:每个 worker 独立 listen socket,避免 accept_mutex 争用,显著提升多核扩展性。
  • worker_connections 65535 × 8 workers:理论可承载数十万并发连接。
  • open_file_cache:缓存静态文件的 fd 与元信息,减少 stat()/open() 系统调用。
  • gzip_comp_level 6 + 扩展 gzip_types:文本类资源压缩率更高(细节见 4.4)。
  • 访问日志改为 64KB 缓冲 + 1s 刷盘:把磁盘 IO 从"每条请求一次 write"变成"批量写",对 QPS 影响显著。

五、调优后压测:同样的命令,翻倍的结果

5.1 c=2000:QPS 几乎翻倍,延迟腰斩

Requests/sec: 294378.76         <-- 优化前 147,823  →  2.0×
Latency Distribution
  50%    5.86ms                 <-- 优化前 12.57ms
  99%   13.49ms                 <-- 优化前 29.76ms

5.2 c=8000:错误清零,吞吐再上台阶

Requests/sec: 244828.64         <-- 优化前 131,988(且带错误)→ 1.85×
Latency Distribution
  99%  191.04ms
(无任何 Socket errors)        <-- 优化前 read 5972 + timeout 3415

注意 p99 在 c=8000 时数值偏高(191ms),但错误率从有到无才是质变:优化前大量连接在排队/重建中超时或读失败,优化后全部成功完成,这才是生产最关心的稳定性指标。

5.3 gzip:被低估的"带宽放大器"

对一份 1MB 的可压缩文本资源(/big.html)做对比:

配置客户端收到体积说明
原始(无压缩)1,048,576 B裸文件
默认 gzip(comp_level 1)11,707 B优化前默认行为
调优后 gzip(comp_level 6)5,535 B压缩率再翻倍

验证命令与真实回显:

# 无 Accept-Encoding:返回原始 1MB
curl -s -o /dev/null -w "size=%{size_download}\n" http://127.0.0.1/big.html
# size=1048576

# 带 gzip 请求:仅 5.5KB
curl -s --compressed -H "Accept-Encoding: gzip" -o /dev/null -w "size=%{size_download}\n" http://127.0.0.1/big.html
# size=5535

对文本/JSON/JS 类接口而言,这等于把出口带宽压力降低约 190 倍,在按流量计费的云环境里直接省钱。


六、前后对比总表

指标优化前优化后变化
somaxconn40966553516×
worker 软 nofile10246553564×
worker_connections7686553585×
c=2000 QPS147,823294,379+99%
c=2000 p9929.76ms13.49ms-55%
c=8000 QPS131,988244,829+85%
c=8000 错误数93870清零
1MB 文本出口1,048,576 B5,535 B-99.5%

七、经验总结

  1. 瓶颈往往在"配置默认值"而非硬件。 本例中 64× 的描述符上限、16× 的 accept 队列,是免费的、立竿见影的红利。
  2. 先看 limits,再看 sysctl,最后动 nginx.conf 顺序反了,内核/系统层上限会"卡住"应用层优化。
  3. reuseport 是多核时代的必选项,它让每个 worker 有独立监听队列,避免惊群与锁竞争。
  4. gzip 不是"锦上添花"而是"降本增效",对文本类流量收益巨大。
  5. 压测要记录错误率,而不只是 QPS。 没有错误率的吞吐是"伪高吞吐"。

复现脚本与完整配置已沉淀在服务器的 /etc/nginx/nginx.conf/etc/sysctl.d/99-nginx-tuning.conf。本篇所有 wrk / curl 输出均来自真实服务器,未经任何修饰。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值