0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Nginx高并发连接调优实战手册

马哥Linux运维 来源:马哥Linux运维 2026-03-16 15:28 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、概述

1.1 背景介绍

Nginx 的高性能源自其事件驱动架构。与 Apache 的"每连接一线程"模型不同,Nginx 使用单线程事件循环处理数千个并发连接。理解这套架构是调优的前提。

Nginx 采用 master-worker 进程模型。master 进程负责读取配置、管理 worker 进程、绑定端口。实际的连接处理和请求处理由 worker 进程完成。每个 worker 进程运行一个事件循环,使用操作系统提供的 I/O 多路复用机制(Linux 上是 epoll)监听所有连接上的事件,在单个线程内高效调度数千个连接。

epoll 的工作原理

epoll 是 Linux 2.6 引入的 I/O 事件通知机制,相比 select/poll 有两个核心优势。第一,epoll 使用红黑树管理被监控的文件描述符,添加和删除操作的时间复杂度是 O(log n),而 select/poll 每次调用都要将整个描述符集合从用户空间复制到内核空间。第二,epoll 使用回调机制,内核在事件发生时将就绪的描述符加入就绪链表,epoll_wait 只需要检查就绪链表,时间复杂度是 O(就绪事件数),而非 O(所有被监控的描述符数)。

在 10 万并发连接的场景下,每次事件循环 select 需要遍历 10 万个描述符,而 epoll 只需要处理实际有事件的那几十个描述符。这就是 Nginx 能在单个 worker 进程中处理数万并发连接的根本原因。

连接处理的全链路分析:

一个 HTTP 请求从到达服务器到返回响应,经历以下阶段:

客户端 → 内核网络栈 → Nginx accept → 读取请求 → 处理请求 → 代理到上游 → 上游响应 → 返回客户端

具体到系统层面:

1. 数据包到达网卡,触发硬中断
2. 内核协议栈处理 TCP 三次握手,连接进入 accept 队列
3. Nginx worker 的 epoll_wait 返回,调用 accept() 获取新连接
4. 新连接的 fd 加入 epoll 监控
5. 数据到达,epoll 通知 worker 读取请求
6. Nginx 解析 HTTP 请求,匹配 location 规则
7. 如果是反向代理,建立到 upstream 的连接
8. 将请求转发到 upstream,等待响应
9. 从 upstream 读取响应,通过缓冲区暂存
10. 将响应写回客户端连接
11. 如果是 keepalive 连接,保持连接等待下一个请求
12. 连接关闭,fd 从 epoll 中移除

并发瓶颈的四个层级:

高并发场景下的瓶颈不会只出现在 Nginx 配置层面。完整的瓶颈分析需要覆盖四个层级:

系统层瓶颈:文件描述符数量限制(每个连接消耗一个 fd)、内核网络栈参数(TCP backlog、端口范围、连接跟踪表)、内存限制(每个连接需要内核和用户空间各分配缓冲区)。

Nginx 层瓶颈:worker 进程数、每个 worker 的最大连接数、事件处理模型配置、keepalive 参数、缓冲区大小。

上游层瓶颈:到 upstream 的连接池配置、upstream keepalive 连接数、upstream 响应时间、连接超时设置。

应用层瓶颈:后端应用的处理能力(QPS 上限)、数据库连接池、缓存命中率、应用线程池/协程池大小。

Nginx 调优的核心思路是:确保每一层都不会成为瓶颈,让请求能够顺畅地通过整条链路。

1.2 核心概念

连接与请求的区别:

一个 TCP 连接(connection)上可以承载多个 HTTP 请求(request)。HTTP/1.1 的 keepalive 机制允许在同一个连接上串行发送多个请求。HTTP/2 更进一步,在同一个连接上可以并行发送多个请求(通过多路复用 stream)。因此 Nginx 的 worker_connections 参数限制的是并发连接数而非并发请求数。

反向代理场景的连接消耗:

当 Nginx 作为反向代理时,每个客户端请求需要消耗两个连接:一个是客户端到 Nginx 的前端连接,一个是 Nginx 到 upstream 的后端连接。因此实际能处理的并发客户端请求数约为 worker_connections / 2。如果启用了 upstream keepalive 连接池,后端连接可以复用,实际能处理的并发数会高于这个理论值。

背压(Backpressure)机制:

Nginx 的 proxy_buffer 机制实现了上游和下游之间的背压解耦。当 upstream 的响应速度快于客户端的接收速度时,Nginx 将响应缓存在 proxy_buffer 中,尽快释放 upstream 连接。如果缓冲区也满了,Nginx 会暂停从 upstream 读取数据,形成自然的背压。这个机制使得一个慢客户端不会长时间占用 upstream 的连接资源。

1.3 适用场景

Web 服务器/反向代理在高并发下出现 502/504 错误

服务器连接数达到上限,新请求被拒绝(Connection refused)

TIME_WAIT 连接堆积导致端口耗尽

upstream 响应正常但客户端体感延迟高

压测时 QPS 无法随资源线性增长

HTTP/2 或 HTTP/3 环境下的特定调优需求

1.4 环境要求

组件 版本要求 说明
操作系统 Ubuntu 24.04 LTS / Rocky Linux 9.5 内核 6.12+
Linux 内核 6.12+ 支持 io_uring、BBR v3、最新 TCP 优化
Nginx 1.27.x 主线版本,包含最新特性
OpenSSL 3.3+ TLS 1.3 和 HTTP/3 (QUIC) 支持
systemd 256+ 进程管理和资源限制
wrk 4.2+ HTTP 压测工具
vegeta 12.12+ HTTP 负载测试工具
Prometheus 3.x 监控指标采集
Grafana 11.x 监控仪表盘
nginx-module-vts 或 nginx-prometheus-exporter 最新版 Nginx 指标暴露

二、详细步骤

2.1 系统层调优

2.1.1 文件描述符限制

每个网络连接消耗一个文件描述符。如果要支持 10 万并发连接,Nginx worker 进程需要能打开至少 10 万个文件描述符。

# 查看系统级别的文件描述符限制
cat /proc/sys/fs/file-max
# 默认值通常足够大(数十万到数百万),但需要确认

# 查看系统当前已使用的文件描述符数
cat /proc/sys/fs/file-nr
# 输出格式:已分配 空闲 最大值

# 查看 Nginx 进程的文件描述符限制
# 先获取 worker 进程 PID
ps aux | grep"nginx: worker"
# 再查看限制
cat /proc//limits | grep"Max open files"

调整文件描述符限制:

# 方法 1:通过 sysctl 调整系统级限制
cat << 'EOF' | sudo tee /etc/sysctl.d/99-nginx-tuning.conf
# 系统级最大文件描述符数
fs.file-max = 2097152

# inotify 监控实例数(与 Nginx 无直接关系,但大量文件监控场景需要)
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 524288
EOF
sudo sysctl --system

# 方法 2:通过 limits.conf 调整用户级限制
cat << 'EOF' | sudo tee /etc/security/limits.d/99-nginx.conf
# Nginx 运行用户的文件描述符限制
nginx    soft    nofile    1048576
nginx    hard    nofile    1048576
root     soft    nofile    1048576
root     hard    nofile    1048576
*        soft    nofile    1048576
*        hard    nofile    1048576
EOF

# 方法 3:通过 systemd 单元配置(推荐,精准控制 Nginx 进程)
sudo mkdir -p /etc/systemd/system/nginx.service.d/
cat << 'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Service]
LimitNOFILE=1048576
EOF
sudo systemctl daemon-reload
sudo systemctl restart nginx

# 验证生效
cat /proc/$(pgrep -f "nginx: master")/limits | grep "Max open files"
# 预期输出:Max open files            1048576              1048576              files

2.1.2 内核网络参数调优

# 高并发 Nginx 服务器的内核参数调优
cat << 'EOF' | sudo tee /etc/sysctl.d/99-nginx-network.conf

# ============ TCP 连接相关 ============

# TCP 全连接队列长度(accept 队列)
# 当 Nginx accept() 来不及处理时,新连接在这里排队
# 默认 128,高并发场景远远不够
net.core.somaxconn = 65535

# TCP SYN 半连接队列长度
# 三次握手过程中等待 ACK 的连接在这里排队
net.ipv4.tcp_max_syn_backlog = 65535

# 允许 TIME_WAIT 状态的 socket 被快速回收复用
# 只影响连接到外部服务器的连接(Nginx 到 upstream)
net.ipv4.tcp_tw_reuse = 1

# 本地端口范围(Nginx 连接 upstream 时需要本地端口)
# 默认 32768-60999,约 2.8 万个端口
# 扩大到 1024-65535,约 6.4 万个端口
net.ipv4.ip_local_port_range = 1024 65535

# TCP FIN_WAIT2 超时时间(秒)
# 默认 60 秒,高并发下可以适当缩短
net.ipv4.tcp_fin_timeout = 15

# TCP keepalive 参数(系统默认值,Nginx 有自己的 keepalive 配置)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# ============ 缓冲区相关 ============

# 网络设备的接收队列长度
net.core.netdev_max_backlog = 65535

# 默认和最大的 socket 缓冲区大小
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# TCP 缓冲区自动调整范围:最小值  默认值  最大值(字节)
net.ipv4.tcp_rmem = 4096 131072 16777216
net.ipv4.tcp_wmem = 4096 131072 16777216

# 系统总的 TCP 内存页数限制
net.ipv4.tcp_mem = 786432 1048576 1572864

# ============ 拥塞控制 ============

# 启用 BBR 拥塞控制算法(Linux 4.9+)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# ============ 连接跟踪 ============

# 连接跟踪表大小(如果使用了 iptables/nftables)
# 每个连接跟踪条目约占 300 字节
# 10 万连接需要约 30MB 内存
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 600
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

# ============ 其他 ============

# 允许更多的 SYN 重试
net.ipv4.tcp_synack_retries = 2

# 启用 TCP 快速打开(TFO),减少握手延迟
net.ipv4.tcp_fastopen = 3

# 增大 ARP 缓存
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384
EOF

sudo sysctl --system

# 验证关键参数
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog 
    net.ipv4.ip_local_port_range net.ipv4.tcp_congestion_control

2.1.3 验证 BBR 拥塞控制

# 确认 BBR 模块已加载
lsmod | grep bbr

# 如果没有加载
sudo modprobe tcp_bbr

# 确认当前使用的拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# 预期输出:net.ipv4.tcp_congestion_control = bbr

# 查看可用的拥塞控制算法
sysctl net.ipv4.tcp_available_congestion_control

# BBR 相比 CUBIC 的优势:
# - 基于带宽和 RTT 估计而非丢包率
# - 在高延迟和有损网络中表现更好
# - 能更好地利用可用带宽
# - 对 buffer 膨胀(bufferbloat)有更好的抑制

2.2 Nginx 全局参数调优

2.2.1 worker 进程配置

# 文件路径:/etc/nginx/nginx.conf

# worker 进程数
# auto 会根据 CPU 核心数自动设置
# 在纯代理场景下设为 CPU 核心数
# 如果有大量 CPU 密集操作(如 SSL 握手、gzip 压缩),可以设为核心数的 1-2 倍
worker_processes auto;

# 绑定 worker 进程到特定 CPU 核心
# 减少 CPU 缓存失效和上下文切换
# auto 自动分配(Nginx 1.9.10+)
worker_cpu_affinity auto;

# 每个 worker 进程的最大文件描述符数
# 必须大于等于 worker_connections
worker_rlimit_nofile 1048576;

# 错误日志级别(高并发下 warn 或 error 即可,info/debug 会产生大量日志)
error_log /var/log/nginx/error.log warn;

# PID 文件
pid /run/nginx.pid;

2.2.2 事件模型配置

events {
  # 每个 worker 的最大并发连接数
  # 这个数字包含所有连接:客户端连接 + upstream 连接 + 本地文件 fd
  # 反向代理场景:可服务的并发客户端数 ≈ worker_connections / 2
  # 10 万并发需要:worker_connections >= 200000 / worker_processes
  worker_connections 65535;

  # 使用 epoll 事件模型(Linux 默认,显式指定更清晰)
  use epoll;

  # 允许一个 worker 一次 accept 多个连接
  # 减少 epoll_wait 的调用次数,提高 accept 效率
  multi_accept on;

  # accept 互斥锁
  # off:所有 worker 都监听同一个端口,由内核调度(reuseport 更优)
  # Nginx 1.11.3+ 配合 reuseport 时建议关闭
  accept_mutex off;
}

reuseport 优化:

# 在 listen 指令中启用 reuseport
# reuseport 让每个 worker 进程拥有独立的 listen socket
# 内核在 TCP 层面做负载均衡,避免惊群效应
server {
  listen 80 reuseport;
  listen 443 ssl reuseport;
  # ...
}

# reuseport 的效果:
# - 消除 accept_mutex 锁竞争
# - 内核级别的 worker 间负载均衡
# - 在高并发下(>10000 连接/秒)提升 2-3 倍的新建连接能力

2.2.3 HTTP 核心配置

http {
  # ============ 基础配置 ============

  # MIME 类型
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # 日志格式(高并发下日志 I/O 也是瓶颈之一)
  log_format main '$remote_addr - $remote_user [$time_local] '
          '"$request" $status $body_bytes_sent '
          '"$http_referer" "$http_user_agent" '
          '$request_time $upstream_response_time '
          '$connection $connection_requests';

  # 访问日志缓冲写入(减少 I/O 次数)
  access_log /var/log/nginx/access.log main buffer=64k flush=5s;

  # 高并发压测时可以临时关闭访问日志
  # access_log off;

  # ============ 性能配置 ============

  # 使用 sendfile 系统调用传输文件(零拷贝)
  sendfile on;

  # 配合 sendfile 使用,将多个小数据块合并为一个 TCP 包发送
  tcp_nopush on;

  # 禁用 Nagle 算法,减少小数据包的延迟
  # 与 tcp_nopush 配合:先用 nopush 攒数据,最后一个包用 nodelay 立即发送
  tcp_nodelay on;

  # ============ 连接管理 ============

  # 客户端 keepalive 超时时间(秒)
  # 连接空闲超过此时间后关闭
  # 高并发下不宜设太长,否则空闲连接占用过多 fd
  keepalive_timeout 65;

  # 单个 keepalive 连接上允许的最大请求数
  # 达到后关闭连接,防止单个连接长期占用资源
  keepalive_requests 1000;

  # keepalive 连接的空闲超时(仅 Nginx 1.19.10+)
  # 与 keepalive_timeout 区别:这个是 upstream keepalive 的参数
  # keepalive_time 1h;

  # ============ 超时配置 ============

  # 客户端请求体读取超时(秒)
  client_body_timeout 30;

  # 客户端请求头读取超时(秒)
  client_header_timeout 15;

  # 向客户端发送响应的超时(两次 write 操作之间的间隔)
  send_timeout 30;

  # ============ 缓冲区配置 ============

  # 客户端请求体的缓冲区大小
  client_body_buffer_size 16k;

  # 客户端请求头的缓冲区大小
  client_header_buffer_size 4k;

  # 大请求头的缓冲区
  large_client_header_buffers 4 16k;

  # 最大请求体大小(文件上传限制)
  client_max_body_size 100m;

  # ============ 压缩配置 ============

  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 4;
  gzip_min_length 1000;
  gzip_types text/plain text/css application/json application/javascript
       text/xml application/xml application/xml+rss text/javascript
       image/svg+xml;

  # ============ 连接关闭控制 ============

  # 延迟关闭(lingering close)
  # 确保在关闭连接前读完客户端发送的剩余数据
  # 防止客户端收到 RST 导致的数据丢失
  lingering_close on;
  lingering_time 30s;
  lingering_timeout 5s;

  # 对超时连接发送 RST 而非 FIN
  # 减少 TIME_WAIT 状态的连接数
  # 仅对超时连接生效,正常连接仍走优雅关闭
  reset_timedout_connection on;

  # 包含其他配置文件
  include /etc/nginx/conf.d/*.conf;
}

2.3 上游连接池配置

upstream keepalive 是高并发调优中最容易被忽略但效果最显著的配置项。

# upstream 配置示例
upstream backend {
  # 后端服务器列表
  server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
  server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
  server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;

  # keepalive 连接池大小
  # 每个 worker 进程保持的到 upstream 的空闲 keepalive 连接数
  # 这不是最大连接数,而是"空闲连接缓存"大小
  # 当请求量超过 keepalive 数时,多余的连接在使用完后会被关闭
  #
  # 计算方法:
  # keepalive >= 平均并发请求数 / worker_processes
  # 但不宜设太大,否则空闲连接占用过多服务端资源
  keepalive 64;

  # 每个 keepalive 连接上的最大请求数(Nginx 1.15.3+)
  # 达到后连接被关闭并重新建立
  keepalive_requests 10000;

  # keepalive 连接的最大存活时间(Nginx 1.19.10+)
  # 防止长时间复用同一个连接
  keepalive_time 1h;

  # keepalive 连接空闲超时(Nginx 1.15.3+)
  # 空闲超过此时间的连接会被回收
  keepalive_timeout 60s;
}

server {
  listen 80;
  server_name api.example.com;

  location / {
    proxy_pass http://backend;

    # 使用 HTTP/1.1 到 upstream(keepalive 需要 HTTP/1.1)
    proxy_http_version 1.1;

    # 清除 Connection 头,防止客户端的 "Connection: close" 传递到 upstream
    proxy_set_header Connection "";

    # 超时配置
    proxy_connect_timeout 5s;   # 连接 upstream 的超时
    proxy_send_timeout 30s;    # 发送请求到 upstream 的超时
    proxy_read_timeout 60s;    # 等待 upstream 响应的超时

    # 代理缓冲区配置
    proxy_buffering on;
    proxy_buffer_size 8k;     # 响应头的缓冲区
    proxy_buffers 32 16k;     # 响应体的缓冲区(32 个 16k 的块)
    proxy_busy_buffers_size 64k; # 在响应还未完全读取时可以发送给客户端的缓冲区大小

    # 请求头传递
    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 keepalive 未配置时的问题:

# 没有 keepalive 时,每个请求到 upstream 都会新建 TCP 连接
# 每次新建连接:TCP 三次握手(至少 1.5 RTT)+ 内核分配资源
# 大量短连接导致 TIME_WAIT 堆积

# 查看 TIME_WAIT 连接数
ss -s | grep"TIME-WAIT"
# 或
ss -tn state time-wait | wc -l

# 查看到 upstream 的 TIME_WAIT
ss -tn state time-wait dst 10.0.1.10
ss -tn state time-wait dst 10.0.1.11

# 如果 TIME_WAIT 数量超过本地端口范围(默认约 28000 个端口)
# 新连接会因为无法分配源端口而失败
# 表现为 Nginx 报 502 错误,日志中出现 "cannot assign requested address"

2.4 限流限速配置

http {
  # ============ 连接数限制 ============

  # 定义限制区域(基于客户端 IP)
  # zone=conn_limit:10m 表示使用 10MB 共享内存存储状态
  # 每个 IP 状态约占 64 字节,10MB 可以跟踪约 16 万个 IP
  limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

  # 基于服务名的连接数限制
  limit_conn_zone $server_name zone=server_conn_limit:10m;

  # ============ 请求速率限制 ============

  # 定义速率限制区域
  # rate=100r/s 表示每秒 100 个请求
  limit_req_zone $binary_remote_addr zone=req_limit:20m rate=100r/s;

  # API 接口的速率限制(更严格)
  limit_req_zone $binary_remote_addr zone=api_limit:20m rate=30r/s;

  server {
    listen 80;

    # 每个 IP 最多 200 个并发连接
    limit_conn conn_limit 200;

    # 每个 server 最多 50000 个并发连接
    limit_conn server_conn_limit 50000;

    # 限流错误码(默认 503)
    limit_conn_status 429;
    limit_req_status 429;

    location / {
      # 请求速率限制
      # burst=200 允许突发 200 个请求进入队列
      # nodelay 立即处理突发请求(不延迟排队)
      limit_req zone=req_limit burst=200 nodelay;

      proxy_pass http://backend;
    }

    location /api/ {
      # API 接口更严格的速率限制
      limit_req zone=api_limit burst=50 nodelay;

      proxy_pass http://backend;
    }
  }
}

2.5 HTTP/2 调优

server {
  listen 443 ssl http2 reuseport;
  server_name www.example.com;

  # SSL 证书
  ssl_certificate /etc/nginx/ssl/cert.pem;
  ssl_certificate_key /etc/nginx/ssl/key.pem;

  # SSL 优化
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256ECDHE-ECDSA-AES256-GCM-SHA384';
  ssl_prefer_server_ciphers off;

  # SSL 会话缓存(减少 TLS 握手次数)
  ssl_session_cache shared50m;
  ssl_session_timeout 1d;
  ssl_session_tickets on;

  # OCSP Stapling(减少客户端的证书验证延迟)
  ssl_stapling on;
  ssl_stapling_verify on;

  # HTTP/2 特定参数
  # 单连接上的最大并发 stream 数
  http2_max_concurrent_streams 128;

  # HTTP/2 连接的最大请求数
  keepalive_requests 10000;

  location / {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
  }
}

2.6 HTTP/3 (QUIC) 配置

# Nginx 1.25.0+ 原生支持 HTTP/3
# 需要使用 --with-http_v3_module 编译(或使用官方预编译包)

server {
  # HTTP/3 使用 UDP 协议
  listen 443 quic reuseport;
  # HTTP/2 兼容
  listen 443 ssl http2;

  server_name www.example.com;

  ssl_certificate /etc/nginx/ssl/cert.pem;
  ssl_certificate_key /etc/nginx/ssl/key.pem;

  # HTTP/3 需要 TLS 1.3
  ssl_protocols TLSv1.2 TLSv1.3;

  # 通知客户端支持 HTTP/3
  add_header Alt-Svc 'h3=":443"; ma=86400';

  # QUIC 特定参数
  # quic_retry on; # 启用地址验证(防止 DDoS)

  location / {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
  }
}
# 验证 HTTP/3 支持
curl --http3 https://www.example.com/ -I

# 如果 curl 不支持 HTTP/3,使用 h3 测试工具
# 或在浏览器开发者工具中查看 Protocol 列

2.7 启动和验证

# 检查 Nginx 配置语法
sudo nginx -t

# 预期输出:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 查看编译参数(确认支持的模块)
nginx -V 2>&1 | tr' ''
'| grep -E"^--with"

# 重载配置(不中断服务)
sudo nginx -s reload

# 验证 worker 进程数
ps aux | grep"nginx: worker"| grep -v grep | wc -l

# 验证 worker 的文件描述符限制
forpidin$(pgrep -f"nginx: worker");do
 echo"PID$pid:$(cat /proc/$pid/limits | grep 'Max open files' | awk '{print $5}')"
done

# 验证监听端口
ss -tlnp | grep nginx

# 验证 reuseport 是否生效(应该看到每个 worker 都有独立的 listen socket)
ss -tlnp | grep":80"| wc -l
# 如果启用了 reuseport,数量应等于 worker 进程数

# 验证 keepalive 配置
curl -v -H"Connection: keep-alive"http://localhost/ 2>&1 | grep -i"keep-alive"

# 快速压测验证
# 使用 wrk 进行基准测试
wrk -t4 -c1000 -d30s http://localhost/

三、示例代码和配置

3.1 完整配置示例

3.1.1 高并发反向代理完整配置

# 文件路径:/etc/nginx/nginx.conf
# 适用场景:10 万级并发的反向代理服务器
# 硬件规格参考:8 核 16GB,千兆网络

user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 1048576;

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

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

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # 日志格式
  log_format main '$remote_addr - [$time_local] '
          '"$request" $status $body_bytes_sent '
          'rt=$request_time uct=$upstream_connect_time '
          'urt=$upstream_response_time '
          'conn=$connection reqs=$connection_requests';

  # 日志缓冲写入
  access_log /var/log/nginx/access.log main buffer=64k flush=5s;

  # 基础性能
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;

  # 连接管理
  keepalive_timeout 65;
  keepalive_requests 1000;
  reset_timedout_connection on;

  # 超时
  client_body_timeout 30;
  client_header_timeout 15;
  send_timeout 30;

  # 缓冲区
  client_body_buffer_size 16k;
  client_header_buffer_size 4k;
  large_client_header_buffers 4 16k;
  client_max_body_size 50m;

  # 压缩
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 4;
  gzip_min_length 1000;
  gzip_types text/plain text/css application/json application/javascript
       text/xml application/xml text/javascript image/svg+xml;

  # 限流
  limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
  limit_req_zone $binary_remote_addr zone=req_per_ip:20m rate=200r/s;
  limit_conn_status 429;
  limit_req_status 429;

  # upstream 定义
  upstream app_backend {
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s weight=5;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s weight=5;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s weight=3;

    keepalive 128;
    keepalive_requests 10000;
    keepalive_timeout 60s;
  }

  # 默认 server(拒绝未匹配的请求)
  server {
    listen 80 default_server;
    server_name _;
    return 444;
  }

  # 主站点
  server {
    listen 80 reuseport;
    server_name www.example.com api.example.com;

    # 连接限制
    limit_conn conn_per_ip 300;

    # 状态监控端点
    location /nginx_status {
      stub_status on;
      allow 10.0.0.0/8;
      deny all;
    }

    # 健康检查端点
    location /health {
      access_log off;
      return 200 "OK
";
    }

    # 静态文件
    location /static/ {
      alias /var/www/static/;
      expires 30d;
      add_header Cache-Control "public, immutable";
      access_log off;
    }

    # API 代理
    location /api/ {
      limit_req zone=req_per_ip burst=100 nodelay;

      proxy_pass http://app_backend;
      proxy_http_version 1.1;
      proxy_set_header Connection "";

      proxy_connect_timeout 5s;
      proxy_send_timeout 30s;
      proxy_read_timeout 60s;

      proxy_buffering on;
      proxy_buffer_size 8k;
      proxy_buffers 32 16k;
      proxy_busy_buffers_size 64k;

      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 返回错误时尝试下一个服务器
      proxy_next_upstream error timeout http_502 http_503;
      proxy_next_upstream_tries 2;
      proxy_next_upstream_timeout 10s;
    }

    # 默认代理
    location / {
      limit_req zone=req_per_ip burst=200 nodelay;

      proxy_pass http://app_backend;
      proxy_http_version 1.1;
      proxy_set_header Connection "";

      proxy_connect_timeout 5s;
      proxy_send_timeout 30s;
      proxy_read_timeout 60s;

      proxy_buffering on;
      proxy_buffer_size 8k;
      proxy_buffers 16 16k;
      proxy_busy_buffers_size 32k;

      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;
    }
  }
}

3.2 实际应用案例

案例一:worker_connections 不足导致 502

场景描述:某电商平台的 Nginx 反向代理在促销活动期间频繁返回 502 错误。Nginx error.log 中出现大量 "worker_connections are not enough" 警告。后端应用服务器负载正常,响应时间也正常。

排查过程:

# 查看 Nginx 错误日志
tail -100 /var/log/nginx/error.log | grep -i"connections"
# 2026/03/13 1401 [alert] 1234#1234: 768 worker_connections are not enough

# 查看当前 Nginx 配置
grep worker_connections /etc/nginx/nginx.conf
# worker_connections 768;  <- 默认值太小

# 查看 worker 进程数
grep worker_processes /etc/nginx/nginx.conf
# worker_processes 4;

# 当前最大并发连接数 = 4 * 768 = 3072 个连接
# 反向代理每个请求消耗 2 个连接,实际只能服务约 1536 个并发请求

# 查看当前实际连接数
ss -s
# TCP:   5432 (estab 4210, closed 890, orphaned 12, timewait 890)

# 查看 Nginx 连接状态
curl -s http://localhost/nginx_status
# Active connections: 3891
# server accepts handled requests
#  2847362 2847362 15823451
# Reading: 42 Writing: 312 Waiting: 3537

解决方案:

# 第一步:调整 worker_connections
# 编辑 /etc/nginx/nginx.conf
# 将 worker_connections 从 768 调整到 65535

# 第二步:同时调整系统层限制
# 文件描述符
cat << 'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Service]
LimitNOFILE=1048576
EOF

# 内核参数
echo"net.core.somaxconn = 65535" | sudo tee -a /etc/sysctl.d/99-nginx.conf
sudo sysctl --system

# 第三步:在 nginx.conf 中添加
# worker_rlimit_nofile 1048576;

# 第四步:重载配置
sudo systemctl daemon-reload
sudo nginx -t && sudo nginx -s reload

# 第五步:验证
# 新的最大并发:4 * 65535 = 262140 个连接
# 反向代理模式:约 131070 个并发请求
cat /proc/$(pgrep -f "nginx: worker" | head -1)/limits | grep "Max open files"

案例二:upstream keepalive 未配置导致 TIME_WAIT 堆积

场景描述:Nginx 反向代理服务器在高峰期频繁出现 502 错误,error.log 中记录 "cannot assign requested address while connecting to upstream"。后端服务正常,但 Nginx 服务器上有数万个 TIME_WAIT 连接。

排查过程:

# 查看 TIME_WAIT 连接数
ss -s | grep TIME-WAIT
# TCP:  48291 (estab 3200, closed 2100, orphaned 5, timewait 43002)

# 查看到 upstream 的 TIME_WAIT
ss -tn state time-wait dst 10.0.1.10 | wc -l
# 14523

ss -tn state time-wait dst 10.0.1.11 | wc -l
# 14891

ss -tn state time-wait dst 10.0.1.12 | wc -l
# 13588

# 查看本地端口范围
sysctl net.ipv4.ip_local_port_range
# net.ipv4.ip_local_port_range = 32768  60999
# 可用端口约 28000 个
# 每个目标 IP 的 TIME_WAIT 已接近端口范围上限

# 查看 Nginx upstream 配置
grep -A 10"upstream"/etc/nginx/conf.d/default.conf
# upstream backend {
#   server 10.0.1.10:8080;
#   server 10.0.1.11:8080;
#   server 10.0.1.12:8080;
# }
# 没有 keepalive 配置,每个请求都新建 TCP 连接到 upstream

# 查看 proxy_http_version
grep"proxy_http_version"/etc/nginx/conf.d/default.conf
# 没有设置,默认是 HTTP/1.0,不支持 keepalive

解决方案:

# 第一步:添加 upstream keepalive

# 修改 upstream 配置
# upstream backend {
#   server 10.0.1.10:8080;
#   server 10.0.1.11:8080;
#   server 10.0.1.12:8080;
#   keepalive 128;
#   keepalive_requests 10000;
#   keepalive_timeout 60s;
# }

# 第二步:在 location 中启用 HTTP/1.1 和清除 Connection 头
# location / {
#   proxy_pass http://backend;
#   proxy_http_version 1.1;
#   proxy_set_header Connection "";
#   ...
# }

# 第三步:扩大本地端口范围(兜底措施)
echo"net.ipv4.ip_local_port_range = 1024 65535"| 
  sudo tee -a /etc/sysctl.d/99-nginx.conf

# 第四步:启用 TIME_WAIT 复用
echo"net.ipv4.tcp_tw_reuse = 1"| 
  sudo tee -a /etc/sysctl.d/99-nginx.conf

sudo sysctl --system

# 第五步:重载 Nginx
sudo nginx -t && sudo nginx -s reload

# 验证效果(观察 TIME_WAIT 数量变化)
watch -n 5'ss -s | grep TIME-WAIT'
# 几分钟后 TIME_WAIT 应该逐渐降低

# 配置 keepalive 后的效果:
# 连接被复用,不再频繁新建和关闭
# TIME_WAIT 从 43000 降到 2000 以下
# 502 错误消失

案例三:10 万并发压测调优全过程

场景描述:需要对一个新部署的 Nginx 反向代理进行 10 万并发连接的压力测试。服务器配置为 16 核 32GB,万兆网卡。后端有 8 台应用服务器。目标是支持 10 万并发连接,QPS 达到 5 万以上。

调优过程:

# ============ 第一轮:基准测试 ============

# 使用默认配置进行基准测试
wrk -t8 -c10000 -d60s http://target-server/api/health

# 基准结果(模拟数据):
# Running 1m test @ http://target-server/api/health
#  8 threads and 10000 connections
#  Thread Stats  Avg   Stdev   Max  +/- Stdev
#   Latency  42.3ms  15.2ms  312ms  78.5%
#   Req/Sec  3125   412    4501   72.1%
#  1498762 requests in 1m, 285MB read
#  Socket errors: connect 6752, read 0, write 0, timeout 234
# Requests/sec: 24979.37

# 问题分析:
# 1. 大量连接错误(connect 6752)—— 连接数限制不够
# 2. QPS 约 2.5 万,距离目标 5 万还有差距
# 3. 有超时错误(timeout 234)

# ============ 第二轮:系统层调优 ============

# 应用前面的系统层优化
sudo sysctl -p /etc/sysctl.d/99-nginx-tuning.conf
sudo sysctl -p /etc/sysctl.d/99-nginx-network.conf

# 调整 Nginx 文件描述符限制
sudo mkdir -p /etc/systemd/system/nginx.service.d/
cat << 'EOF' | sudo tee /etc/systemd/system/nginx.service.d/limits.conf
[Service]
LimitNOFILE=1048576
EOF
sudo systemctl daemon-reload

# 再次测试
wrk -t8 -c10000 -d60s http://target-server/api/health

# 第二轮结果:
# Socket errors: connect 0, read 0, write 0, timeout 12
# Requests/sec:  31245.89
# 连接错误消失,QPS 提升到 3.1 万

# ============ 第三轮:Nginx 配置调优 ============

# 调整 worker_connections、添加 reuseport、配置 upstream keepalive
# 使用前面的完整配置模板

sudo nginx -t && sudo nginx -s reload

# 提高并发到 5 万
wrk -t16 -c50000 -d60s http://target-server/api/health

# 第三轮结果:
# Requests/sec:  48923.17
# 平均延迟:25.6ms
# 无连接错误
# QPS 接近 5 万

# ============ 第四轮:精细调优 ============

# 1. 确认压测客户端本身不是瓶颈(使用多台客户端)
# 2. 检查 Nginx 的 CPU 使用率分布
pidstat -p $(pgrep -f "nginx: worker" | tr '
'',') 1 10

# 如果某个 worker CPU 使用率明显高于其他,说明负载不均衡
# 启用 reuseport 后应该比较均衡

# 3. 检查网络瓶颈
sar -n DEV 1 10
# 查看网卡带宽使用率

# 4. 提高到 10 万并发
wrk -t16 -c100000 -d120s http://target-server/api/health

# 最终结果(模拟数据):
# 16 threads and 100000 connections
# Thread Stats   Avg      Stdev     Max   +/- Stdev
#   Latency    35.8ms   18.4ms   520ms    82.3%
#   Req/Sec    3312     578       4892     68.7%
# 6350421 requests in 2m
# Requests/sec:  52920.17
# 无连接错误,无超时错误
# 目标达成

3.2.1 压测与调优自动化脚本

#!/bin/bash
# 文件名:nginx_benchmark.sh
# 功能:Nginx 性能基准测试脚本
# 依赖:wrk, curl, ss
# 用法:./nginx_benchmark.sh  [connections] [duration]

set-euo pipefail

# ============ 参数 ============

TARGET_URL="${1:?用法: $0  [connections] [duration]}"
CONNECTIONS="${2:-1000}"
DURATION="${3:-30s}"
THREADS=$(nproc)
REPORT_DIR="/tmp/nginx_benchmark_$(date +%Y%m%d_%H%M%S)"

mkdir -p"$REPORT_DIR"

echo"========================================"
echo"Nginx 性能基准测试"
echo"========================================"
echo"目标 URL:$TARGET_URL"
echo"并发连接:$CONNECTIONS"
echo"测试时长:$DURATION"
echo"线程数: $THREADS"
echo"报告目录:$REPORT_DIR"
echo"========================================"

# ============ 测试前检查 ============

echo""
echo"[1/5] 测试前环境检查..."

# 检查目标可达
if! curl -sf -o /dev/null -m 5"$TARGET_URL";then
 echo"ERROR: 无法访问$TARGET_URL"
 exit1
fi

# 检查 wrk 工具
if!command-v wrk &> /dev/null;then
 echo"ERROR: wrk 未安装"
 echo"Ubuntu: sudo apt install -y wrk"
 echo"Rocky: 需要从源码编译"
 exit1
fi

# 记录系统状态
echo"系统配置:">"$REPORT_DIR/system_info.txt"
echo"CPU 核心数:$(nproc)">>"$REPORT_DIR/system_info.txt"
echo"内存:$(free -h | grep Mem | awk '{print $2}')">>"$REPORT_DIR/system_info.txt"
echo"somaxconn:$(sysctl -n net.core.somaxconn)">>"$REPORT_DIR/system_info.txt"
echo"file-max:$(sysctl -n fs.file-max)">>"$REPORT_DIR/system_info.txt"
echo"tcp_tw_reuse:$(sysctl -n net.ipv4.tcp_tw_reuse)">>"$REPORT_DIR/system_info.txt"
echo"local_port_range:$(sysctl -n net.ipv4.ip_local_port_range)">>"$REPORT_DIR/system_info.txt"

# ============ 预热 ============

echo""
echo"[2/5] 预热阶段(10 秒)..."
wrk -t"$THREADS"-c100 -d10s"$TARGET_URL"> /dev/null 2>&1

# ============ 正式测试 ============

echo""
echo"[3/5] 正式测试 ($DURATION)..."
wrk -t"$THREADS"-c"$CONNECTIONS"-d"$DURATION"--latency"$TARGET_URL"
  >"$REPORT_DIR/wrk_output.txt"2>&1

# ============ 采集指标 ============

echo""
echo"[4/5] 采集系统指标..."

# 连接状态统计
ss -s >"$REPORT_DIR/ss_summary.txt"2>&1

# TIME_WAIT 统计
ss -tn state time-wait | wc -l >"$REPORT_DIR/timewait_count.txt"2>&1

# Nginx stub_status(如果可用)
curl -sf"http://localhost/nginx_status">"$REPORT_DIR/nginx_status.txt"2>/dev/null ||true

# ============ 输出报告 ============

echo""
echo"[5/5] 测试结果"
echo"========================================"
cat"$REPORT_DIR/wrk_output.txt"
echo""
echo"========================================"
echo"TIME_WAIT 连接数:$(cat "$REPORT_DIR/timewait_count.txt")"
echo""

if[ -f"$REPORT_DIR/nginx_status.txt"];then
 echo"Nginx 状态:"
  cat"$REPORT_DIR/nginx_status.txt"
 echo""
fi

echo"完整报告保存在:$REPORT_DIR/"
echo"========================================"

四、最佳实践和注意事项

4.1 最佳实践

4.1.1 不同业务场景的参数模板

场景 A:API 网关(高 QPS,小请求体)

# 特点:请求小、响应小、延迟敏感
upstream api_backend {
  server 10.0.1.10:8080;
  server 10.0.1.11:8080;
  keepalive 256;     # 较大的连接池
  keepalive_requests 50000;
  keepalive_timeout 120s;
}

server {
  keepalive_timeout 30;  # 较短的客户端 keepalive
  keepalive_requests 500;

  location / {
    proxy_pass http://api_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_connect_timeout 3s;
    proxy_read_timeout 10s;

    # 小缓冲区,因为响应通常不大
    proxy_buffer_size 4k;
    proxy_buffers 8 8k;
  }
}

场景 B:文件下载服务(高带宽,大响应体)

# 特点:大文件、长连接、带宽密集
upstream file_backend {
  server 10.0.1.20:8080;
  server 10.0.1.21:8080;
  keepalive 32;      # 连接数不用太多,但每个连接传输时间长
  keepalive_requests 100;
  keepalive_timeout 300s; # 较长的超时
}

server {
  keepalive_timeout 120;
  client_max_body_size 10g; # 允许大文件上传

  location /download/ {
    proxy_pass http://file_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_read_timeout 600s; # 大文件传输需要较长超时

    # 大缓冲区 + 临时文件缓存
    proxy_buffering on;
    proxy_buffer_size 16k;
    proxy_buffers 64 32k;
    proxy_busy_buffers_size 128k;
    proxy_max_temp_file_size 1024m; # 允许缓存到临时文件
    proxy_temp_path /var/cache/nginx/proxy_temp;
  }
}

场景 C:WebSocket 代理(长连接,双向通信

# 特点:长连接、双向数据、连接数多
map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

upstream ws_backend {
  server 10.0.1.30:8080;
  server 10.0.1.31:8080;
  # WebSocket 不使用 keepalive 连接池
  # 因为 WebSocket 连接是持久化的
}

server {
  location /ws/ {
    proxy_pass http://ws_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # WebSocket 超时要设长,否则空闲连接会被断开
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;

    # 禁用缓冲(WebSocket 需要实时传输)
    proxy_buffering off;
  }
}

4.1.2 灰度调优流程

# 修改 Nginx 配置时的安全流程

# 第一步:在测试环境验证配置
sudo nginx -t

# 第二步:备份当前配置
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d_%H%M%S)

# 第三步:灰度生效
# 如果有多台 Nginx,先在一台上 reload
sudo nginx -s reload

# 第四步:观察指标(至少 10 分钟)
# 关注:错误率、延迟、连接数、CPU/内存

# 第五步:确认无异常后,在其余服务器上逐台 reload

# 第六步:如果发现问题,立即回滚
sudo cp /etc/nginx/nginx.conf.bak.20260313_143000 /etc/nginx/nginx.conf
sudo nginx -t && sudo nginx -s reload

4.1.3 安全加固

# 隐藏 Nginx 版本信息
server_tokens off;

# 安全响应头
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy strict-origin-when-cross-origin always;

# 限制请求方法
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|PATCH)$) {
  return 405;
}

# 禁止访问隐藏文件
location ~ /. {
  deny all;
  access_log off;
  log_not_found off;
}

4.2 注意事项

4.2.1 配置注意事项

worker_connections 与文件描述符的关系:

worker_connections 只是 Nginx 配置层面的限制,实际生效还需要操作系统允许打开那么多文件描述符。必须确保 worker_rlimit_nofile >= worker_connections。推荐设置 worker_rlimit_nofile 为 worker_connections 的 2 倍以上,因为除了网络连接,Nginx 还需要打开日志文件、缓存文件等。

proxy_buffering 的副作用:

proxy_buffering on(默认)会让 Nginx 尽快从 upstream 读取完整响应,释放 upstream 连接。但如果响应很大且客户端接收很慢,Nginx 会将响应缓存到内存甚至磁盘临时文件中。这会增加内存和磁盘 I/O 消耗。对于 Server-Sent Events (SSE) 和流式响应,必须设置 proxy_buffering off。

keepalive_timeout 不宜过长:

客户端 keepalive 超时设得太长会导致大量空闲连接占用 worker_connections 的配额。如果 10 万个客户端都保持 keepalive 但实际只有 1 万个在发请求,那 9 万个空闲连接白白占用了资源。一般 30-120 秒是合理范围。

4.2.2 常见错误

错误现象 原因分析 解决方案
502 Bad Gateway upstream 连接失败或超时 检查 upstream 健康状态,调整 proxy_connect_timeout
504 Gateway Timeout upstream 响应超时 调整 proxy_read_timeout,排查后端性能
"worker_connections are not enough" 并发连接超过 worker_connections 增大 worker_connections,同时调整系统 fd 限制
"cannot assign requested address" 本地端口耗尽(TIME_WAIT 堆积) 启用 upstream keepalive,扩大 ip_local_port_range
"too many open files" 文件描述符限制不足 调整 worker_rlimit_nofile 和系统 limits
"upstream prematurely closed connection" upstream 关闭了 keepalive 连接 确保 upstream keepalive_timeout > Nginx keepalive_timeout
"110: Connection timed out" while connecting to upstream upstream 的 accept 队列满或网络问题 检查 upstream 的 somaxconn 和 backlog
Nginx CPU 100% 某个核 单个 worker 负载过重 启用 reuseport 均衡负载

4.2.3 兼容性问题

HTTP/2 与 upstream:Nginx 到 upstream 的连接目前不支持 HTTP/2(截至 1.27.x),即使客户端使用 HTTP/2。upstream 连接始终使用 HTTP/1.1。如果 upstream 是 gRPC 服务,使用 grpc_pass 指令而非 proxy_pass。

HTTP/3 客户端兼容性:部分老版本浏览器和客户端不支持 HTTP/3。必须同时保留 HTTP/2 监听以确保兼容性。通过 Alt-Svc 头通知支持 HTTP/3 的客户端升级。

TCP Fast Open:需要内核 3.7+ 支持。某些中间网络设备(防火墙、负载均衡器)可能丢弃 TFO 的 SYN 包。在公网环境建议测试后再启用。

reuseport 与热重载:使用 reuseport 时,nginx -s reload 会导致短暂的连接中断(旧 worker 的 listen socket 被关闭,新 worker 创建新的 listen socket)。如果对零停机有严格要求,需要评估影响。

五、故障排查和监控

5.1 故障排查

5.1.1 日志查看

# 查看 Nginx 错误日志(实时跟踪)
sudo tail -f /var/log/nginx/error.log

# 按错误级别过滤
grep'[error]'/var/log/nginx/error.log | tail -20
grep'[crit]'/var/log/nginx/error.log | tail -20
grep'[alert]'/var/log/nginx/error.log | tail -20
grep'[emerg]'/var/log/nginx/error.log | tail -20

# 统计错误类型分布
awk -F'[][]''/[(error|crit|alert|emerg)]/ {print $2}'
  /var/log/nginx/error.log | sort | uniq -c | sort -rn

# 统计 upstream 错误
grep"upstream"/var/log/nginx/error.log | 
  grep -oP'(timed out|connection refused|no live upstreams|prematurely closed)'| 
  sort | uniq -c | sort -rn

# 分析访问日志中的 HTTP 状态码分布
awk'{print $9}'/var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# 分析响应时间分布(需要自定义日志格式包含 $request_time)
awk'{print $NF}'/var/log/nginx/access.log | 
  awk'{
    if ($1 < 0.1) bucket="<100ms";
        else if ($1 < 0.5) bucket="100-500ms";
        else if ($1 < 1) bucket="500ms-1s";
        else if ($1 < 5) bucket="1-5s";
        else bucket=">5s";
    count[bucket]++
  }
  END {for (b in count) print count[b], b}'| sort -rn

5.1.2 实时状态监控

# 使用 stub_status 模块查看实时连接状态
curl -s http://localhost/nginx_status

# 输出示例:
# Active connections: 12456
# server accepts handled requests
# 28473621 28473621 158234512
# Reading: 142 Writing: 1523 Waiting: 10791

# 字段含义:
# Active connections -- 当前活跃连接数(包括 Waiting)
# accepts      -- 总接受连接数
# handled      -- 总处理连接数(handled == accepts 表示没有丢弃连接)
# requests     -- 总请求数(一个连接可以发多个请求)
# Reading      -- 正在读取请求头的连接数
# Writing      -- 正在写响应的连接数
# Waiting      -- keepalive 空闲等待的连接数

# 使用 watch 持续监控
watch -n 1'curl -s http://localhost/nginx_status'

# 编写简单的监控脚本
whiletrue;do
 echo"$(date +%H:%M:%S)$(curl -s http://localhost/nginx_status | 
    awk '/Active/{printf "active=%s ",$3} /Reading/{printf "reading=%s writing=%s waiting=%s",$2,$4,$6}')"
  sleep 5
done

5.1.3 连接状态分析

# 查看 Nginx 进程的连接数
forpidin$(pgrep -f"nginx: worker");do
  fd_count=$(ls /proc/$pid/fd 2>/dev/null | wc -l)
 echo"Worker PID$pid:$fd_countfile descriptors"
done

# 查看各状态的 TCP 连接数
ss -ant | awk'{print $1}'| sort | uniq -c | sort -rn

# 查看到各 upstream 的连接分布
ss -tn | awk'{print $5}'| grep -E"10.0.1.(10|11|12):8080"| 
  sort | uniq -c | sort -rn

# 查看 SYN 队列溢出
netstat -s | grep -i"SYNs to LISTEN"
# 或
nstat -a | grep TcpExtListenOverflows

# 查看 accept 队列溢出
nstat -a | grep TcpExtListenDrops
# 如果这个数字在增长,说明 somaxconn 或 Nginx backlog 不够大

5.2 性能监控

5.2.1 Prometheus 指标采集

使用 nginx-prometheus-exporter:

# 安装 nginx-prometheus-exporter
# 下载地址:https://github.com/nginxinc/nginx-prometheus-exporter/releases

# 运行 exporter(基于 stub_status)
nginx-prometheus-exporter -nginx.scrape-uri=http://localhost/nginx_status &

# exporter 默认监听 9113 端口
curl -s http://localhost:9113/metrics | grep nginx

# 暴露的关键指标:
# nginx_connections_active  -- 活跃连接数
# nginx_connections_accepted -- 总接受连接数(counter)
# nginx_connections_handled  -- 总处理连接数(counter)
# nginx_connections_reading  -- 读取请求头的连接数
# nginx_connections_writing  -- 发送响应的连接数
# nginx_connections_waiting  -- keepalive 空闲连接数
# nginx_http_requests_total  -- 总请求数(counter)

Prometheus 采集配置:

# 文件路径:/etc/prometheus/prometheus.yml(相关片段)

scrape_configs:
-job_name:'nginx'
 scrape_interval:15s
 static_configs:
  -targets:
    -'nginx-server-01:9113'
    -'nginx-server-02:9113'

# 同时采集 node_exporter 的系统指标
-job_name:'node'
 scrape_interval:15s
 static_configs:
  -targets:
    -'nginx-server-01:9100'
    -'nginx-server-02:9100'

5.2.2 关键监控指标

指标名称 正常范围 告警阈值 说明
活跃连接数 取决于业务 > 80% worker_connections 总量 接近上限说明需要扩容
新建连接速率 取决于业务 突增 200% 以上 可能是流量攻击或业务突发
HTTP 5xx 错误率 < 0.1% > 1% 502/504 是最常见的上游问题
请求延迟 P99 < 500ms > 2s 尾部延迟反映最差情况
Worker CPU 使用率 < 80% > 90% 单个 worker 过高说明负载不均
TIME_WAIT 连接数 < 5000 > 20000 持续增长说明 keepalive 配置有问题
accept 队列溢出 0 > 0 且持续增长 需要增大 somaxconn 或 backlog
dropped connections 0 > 0 handled != accepted 说明有连接被丢弃

5.2.3 告警规则

# 文件路径:/etc/prometheus/rules/nginx_alerts.yml

groups:
-name:nginx_alerts
 rules:
  # 连接数接近上限
  -alert:NginxConnectionsHigh
   expr:nginx_connections_active>50000
   for:5m
   labels:
    severity:warning
   annotations:
    summary:"Nginx 活跃连接数过高"
    description:"{{ $labels.instance }}活跃连接{{ $value }},接近配置上限"

  # 5xx 错误率过高
  -alert:NginxHighErrorRate
   expr:|
     rate(nginx_http_requests_total{status=~"5.."}[5m])
     /
     rate(nginx_http_requests_total[5m])
     > 0.01
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"Nginx 5xx 错误率过高"
    description:"{{ $labels.instance }}5xx 错误率{{ $value | humanizePercentage }}"

  # 连接被丢弃
  -alert:NginxConnectionsDropped
   expr:|
     (rate(nginx_connections_accepted[5m]) - rate(nginx_connections_handled[5m])) > 0
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"Nginx 存在丢弃的连接"
    description:"{{ $labels.instance }}正在丢弃连接,每秒约{{ $value }}个"

  # Nginx 进程消失
  -alert:NginxDown
   expr:nginx_up==0
   for:1m
   labels:
    severity:critical
   annotations:
    summary:"Nginx 服务不可用"
    description:"{{ $labels.instance }}Nginx 进程未运行"

5.3 备份与恢复

5.3.1 配置备份

#!/bin/bash
# 文件名:nginx_config_backup.sh
# 功能:备份 Nginx 完整配置

BACKUP_DIR="/backup/nginx/$(date +%Y%m%d_%H%M%S)"
mkdir -p"$BACKUP_DIR"

# 备份配置文件
cp -r /etc/nginx/"$BACKUP_DIR/nginx-config/"

# 备份 SSL 证书
cp -r /etc/nginx/ssl/"$BACKUP_DIR/ssl/"2>/dev/null

# 备份 systemd 覆盖配置
cp -r /etc/systemd/system/nginx.service.d/"$BACKUP_DIR/systemd/"2>/dev/null

# 备份系统调优参数
cp /etc/sysctl.d/99-nginx-*.conf"$BACKUP_DIR/"2>/dev/null
cp /etc/security/limits.d/99-nginx.conf"$BACKUP_DIR/"2>/dev/null

# 记录当前状态
nginx -V >"$BACKUP_DIR/nginx_version.txt"2>&1
nginx -T >"$BACKUP_DIR/nginx_full_config.txt"2>&1

# 压缩
tar czf"${BACKUP_DIR}.tar.gz"-C"$(dirname $BACKUP_DIR)""$(basename $BACKUP_DIR)"
rm -rf"$BACKUP_DIR"

echo"Nginx 配置已备份到${BACKUP_DIR}.tar.gz"

5.3.2 恢复流程

# 1. 解压备份
tar xzf /backup/nginx/20260313_143000.tar.gz -C /tmp/

# 2. 恢复配置
sudo cp -r /tmp/20260313_143000/nginx-config/* /etc/nginx/

# 3. 检查配置语法
sudo nginx -t

# 4. 重载配置
sudo nginx -s reload

# 5. 验证
curl -I http://localhost/

六、总结

6.1 技术要点回顾

Nginx 高并发能力的基础是 epoll 事件驱动模型,单个 worker 进程可以处理数万并发连接,调优时不要盲目增加 worker 数量

系统层调优(文件描述符、somaxconn、端口范围、BBR)是基础,Nginx 配置层面的参数再大也无法突破系统限制

upstream keepalive 是高并发反向代理中效果最显著的优化项,必须配合 proxy_http_version 1.1 和 proxy_set_header Connection "" 使用

TIME_WAIT 堆积的根因通常是 upstream 连接未复用,启用 keepalive 后配合 tcp_tw_reuse 可以有效解决

reuseport 消除了 accept_mutex 的锁竞争,在高新建连接速率场景下提升显著

限流(limit_conn / limit_req)是保护 Nginx 和后端服务的最后一道防线,必须在上线前配置好

不同业务场景(API 网关、文件下载、WebSocket)的调优参数差异很大,不存在万能配置

6.2 进阶学习方向

Nginx 内部机制深入:连接池管理、事件调度器实现、内存池分配策略、变量延迟求值机制。通过阅读 Nginx 源码理解 ngx_event_module 和 ngx_http_module 的交互。

OpenResty / Lua 扩展:在 Nginx 中嵌入 Lua 脚本实现动态路由、复杂限流、A/B 测试、灰度发布。OpenResty 的 cosocket API 支持在 Nginx 中进行非阻塞网络操作。

QUIC/HTTP3 深度调优:QUIC 协议的拥塞控制、0-RTT 连接恢复、连接迁移等特性的调优和生产实践。

6.3 参考资料

Nginx 官方文档: https://nginx.org/en/docs/

Nginx 管理指南: https://docs.nginx.com/nginx/admin-guide/

Linux 网络栈调优: https://www.kernel.org/doc/html/latest/networking/

wrk HTTP 压测工具: https://github.com/wg/wrk

nginx-prometheus-exporter: https://github.com/nginxinc/nginx-prometheus-exporter

BBR 拥塞控制: https://github.com/google/bbr

man 7 tcp / man 7 socket / man 2 epoll_wait

附录

A. 命令速查表

# Nginx 管理
nginx -t                  # 检查配置语法
nginx -T                  # 输出完整配置
nginx -s reload              # 重载配置
nginx -s stop               # 停止服务
nginx -V                  # 查看编译参数

# 系统参数查看
sysctl net.core.somaxconn         # TCP accept 队列
sysctl net.ipv4.ip_local_port_range    # 本地端口范围
sysctl net.ipv4.tcp_tw_reuse        # TIME_WAIT 复用
sysctl fs.file-max             # 系统文件描述符上限
ulimit-n                 # 当前用户文件描述符限制

# 连接状态
ss -s                    # TCP 连接状态汇总
ss -tn state time-wait | wc -l       # TIME_WAIT 数量
ss -tn state established | wc -l      # ESTABLISHED 数量
nstat -a | grep TcpExtListenOverflows   # accept 队列溢出

# Nginx 状态
curl -s http://localhost/nginx_status    # stub_status
curl -s http://localhost:9113/metrics    # Prometheus 指标

# 压测
wrk -t8 -c10000 -d60s http://target/    # wrk 压测

B. 配置参数详解

nginx.conf 核心参数说明:

worker_processes:worker 进程数,auto 根据 CPU 核心数设置

worker_cpu_affinity:CPU 亲和性绑定,auto 自动分配

worker_rlimit_nofile:每个 worker 的文件描述符限制

worker_connections:每个 worker 的最大连接数

multi_accept:是否一次 accept 多个连接

accept_mutex:accept 互斥锁,使用 reuseport 时建议关闭

keepalive_timeout:客户端 keepalive 空闲超时

keepalive_requests:单个 keepalive 连接的最大请求数

reset_timedout_connection:超时连接发 RST 而非 FIN

proxy_http_version:到 upstream 的 HTTP 版本,keepalive 需要 1.1

upstream keepalive:upstream 空闲连接池大小(每 worker)

upstream keepalive_requests:upstream keepalive 连接最大请求数

upstream keepalive_timeout:upstream keepalive 空闲超时

proxy_buffer_size:响应头缓冲区大小

proxy_buffers:响应体缓冲区(块数和每块大小)

limit_conn:并发连接数限制

limit_req:请求速率限制(rate + burst + nodelay)

reuseport:listen 指令的参数,每个 worker 独立 listen socket

C. 术语表

术语 英文 解释
epoll Event Poll Linux 高效 I/O 事件通知机制,支持 O(1) 事件获取
惊群效应 Thundering Herd 多个进程/线程同时被唤醒竞争同一个事件,大部分白白唤醒
reuseport SO_REUSEPORT 允许多个 socket 绑定同一端口,内核层负载均衡
backlog Listen Backlog TCP accept 队列长度,等待被 accept() 的已完成连接
TIME_WAIT TIME_WAIT State TCP 连接关闭后的等待状态,默认持续 60 秒(2MSL)
keepalive HTTP Keep-Alive TCP 连接复用,一个连接承载多个 HTTP 请求
upstream 上游服务器 Nginx 反向代理后面的应用服务器
worker_connections Worker 连接数 每个 worker 进程能同时处理的最大连接数
BBR Bottleneck Bandwidth and RTT Google 开发的 TCP 拥塞控制算法
TFO TCP Fast Open TCP 快速打开,减少握手延迟
QUIC Quick UDP Internet Connections Google 开发的传输层协议,HTTP/3 的基础
stub_status Nginx 状态模块 暴露连接数、请求数等基础指标的内置模块
proxy_buffering 代理缓冲 Nginx 缓存 upstream 响应,解耦上下游速度差异
burst 突发容量 limit_req 中允许的突发请求数,超过 rate 但在 burst 内的请求进入队列

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11806

    浏览量

    219508
  • 操作系统
    +关注

    关注

    37

    文章

    7431

    浏览量

    129597
  • nginx
    +关注

    关注

    0

    文章

    193

    浏览量

    13203

原文标题:Nginx 高并发连接调优实战手册

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Go 语言并发服务设计与性能实战:从万级到百万级并发的演进之路

    10W+ 连接 性能满意度 开发者满意度 89% 微服务采用率 云原生项目中占比 67% 本文将从 并发模型 、 性能优化 、 资源管理 、监控四个维度,分享一套经过多个
    发表于 02-18 19:19

    并发性能是在技术进阶赛道变得厉害的加分项

    并发性能,一定是你在技术进阶赛道变得牛逼的加分项。不论,你是开发,架构还是管理岗,亦或者是其他互联网相关岗位。因为毫不夸张的说,在现在动辄过千万级的
    的头像 发表于 09-18 10:39 1860次阅读

    HarmonyOS测试技术与实战-3D壁纸制作

    HDC 2021华为开发者大会 HarmonyOS测试技术与实战-3D壁纸制作
    的头像 发表于 10-23 15:29 2172次阅读
    HarmonyOS测试技术与<b class='flag-5'>实战</b>-3D壁纸制作<b class='flag-5'>调</b><b class='flag-5'>优</b>

    为什么Nginx可以支持并发

    先说答案,Nginx之所以支持并发,是因为它是基于epoll的异步及非阻塞的事件驱动模型。 在这个模型下,Nginx服务端可以同一时间接收成千上万个客户端请求而不阻塞。这是因为
    的头像 发表于 02-13 10:48 2418次阅读

    Nginx目录结构有哪些

    很多,例如:新浪、网易、 腾讯等。 为什么要用Nginx? 跨平台、配置简单、方向代理、并发连接:处理2-3万并发
    的头像 发表于 11-11 11:27 1514次阅读
    <b class='flag-5'>Nginx</b>目录结构有哪些

    什么场景需要jvm

    JVM是指对Java虚拟机进行性能优化和资源管理,以提高应用程序的运行效率和吞吐量。JVM的场景有很多,下面将详细介绍各种不同的场景。
    的头像 发表于 12-05 11:14 2317次阅读

    鸿蒙开发实战:【性能组件】

    性能组件包含系统和应用框架,旨在为开发者提供一套性能平台,可以用来分析内存、性能等问
    的头像 发表于 03-13 15:12 1495次阅读
    鸿蒙开发<b class='flag-5'>实战</b>:【性能<b class='flag-5'>调</b><b class='flag-5'>优</b>组件】

    手把手教你如何Linux网络参数

    并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃。本文基于真实案例分析,从参数解读、问题诊断到优化实践,手把手教你如何
    的头像 发表于 05-29 09:21 1168次阅读

    Nginx性能优化终极指南

    而worker 进程数默认为 1 。单进程最大连接数为1024。如下图(打开Nginx目录下的/conf/nginx.conf 文档),现在我们来对这两个数值进行
    的头像 发表于 06-16 13:44 1525次阅读
    <b class='flag-5'>Nginx</b>性能优化终极指南

    Nginx在企业环境中的策略

    Nginx作为现代互联网架构中最重要的Web服务器和反向代理服务器,其性能对企业级应用的稳定性和效率至关重要。本指南将从运维实践角度出发,详细介绍Nginx在企业环境中的各种
    的头像 发表于 07-14 11:13 766次阅读

    Nginx并发优化方案

    作为一名在生产环境中摸爬滚打多年的运维工程师,我见过太多因为Nginx配置不当导致的性能瓶颈。今天分享一套完整的Nginx并发优化方案,帮助你的系统从10万QPS突破到百万级别。
    的头像 发表于 08-13 15:51 1200次阅读

    Nginx并发场景下的性能技巧

    在一次双十一大促中,我们的电商平台在活动开始后3分钟内涌入了800万用户,QPS瞬间飙升到50万。就在所有人都捏着一把汗的时候,经过优化的Nginx集群稳稳地扛住了这波流量冲击,CPU使用率始终保持在60%以下。
    的头像 发表于 09-02 16:26 1005次阅读

    实战RK3568性能:如何利用迅为资料压榨NPU潜能-在Android系统中使用NPU

    实战RK3568性能:如何利用迅为资料压榨NPU潜能-在Android系统中使用NPU》
    的头像 发表于 11-07 13:42 982次阅读
    <b class='flag-5'>实战</b>RK3568性能<b class='flag-5'>调</b><b class='flag-5'>优</b>:如何利用迅为资料压榨NPU潜能-在Android系统中使用NPU

    Linux系统内核参数实战指南

    Linux 内核参数是系统性能优化的核心环节。随着云原生架构的普及和硬件性能的飞速提升,默认的内核参数配置往往无法充分发挥系统潜力。在并发 Web 服务、大数据处理、容器化部署等
    的头像 发表于 01-28 14:27 672次阅读

    Ingress Nginx性能配置方案

    Ingress Nginx 是 Kubernetes 集群中最主流的流量入口组件,承担着集群内所有 HTTP/HTTPS 流量的路由和转发。默认配置能应付开发测试环境,但一到生产环境扛并发,各种
    的头像 发表于 02-24 11:50 271次阅读