nginx 高效依赖 epoll 多路复用与系统级协同调优:合理设置 worker 进程数及 CPU 绑定、优化 keepalive 参数控制连接生命周期、提升文件描述符限制、杜绝阻塞操作以保障事件驱动模型。

Nginx 使用 epoll 多路复用机制,本质是让单个 worker 进程高效管理成千上万的并发连接,而非靠增加进程数硬扛。关键不在“用了 epoll”,而在如何配合系统参数、Nginx 配置与业务特征,把它的能力真正释放出来。
合理设置 worker 进程数与 CPU 绑定
worker_processes 应设为 CPU 核心数(或 auto),避免过多进程争抢 CPU 调度开销;每个 worker 只处理自己绑定的连接,减少上下文切换。启用 worker_cpu_affinity 可显式绑定核心,例如 4 核机器可配 worker_cpu_affinity 0001 0010 0100 1000;,让每个 worker 独占一个核。
- 不要盲目设为 higher 值(如 64),超过 CPU 核数反而引发调度抖动
- 若启用了 hyper-threading,需结合实际性能测试判断是否开启逻辑核绑定
- 容器环境注意 cgroup 限制,/proc/cpuinfo 显示的核心数可能与宿主机不一致
调优连接生命周期相关参数
epoll 的高效依赖于连接尽可能“长连接复用”和“快速释放无效连接”。keepalive_timeout 不宜过长(如 75s 是默认值,静态资源可压到 15–30s),否则空闲连接长期占用 worker 连接槽位;同时配合 client_body_timeout、client_header_timeout 防止慢速攻击拖住事件循环。
- 启用 keepalive_requests(如 1000)限制单连接最大请求数,防内存泄漏累积
- 对 API 接口等短连接场景,可适当缩短 keepalive_timeout,甚至设为 0 关闭长连接
- 使用 reset_timedout_connection on; 主动重置超时连接,回收 socket 资源更及时
适配内核与文件描述符限制
epoll 本身无连接数上限,但受限于系统级配置:每个 worker 能处理的并发连接 ≈ worker_rlimit_nofile(Nginx 层) × worker_processes,而该值又受制于系统 ulimit -n 和 fs.file-max。若未调优,常见瓶颈是 “Too many open files” 错误。
- 在 nginx.conf 中设 worker_rlimit_nofile 65535;,并在启动前用 ulimit -n 65535 启动 Nginx
- 系统级追加 /etc/security/limits.conf:nginx soft nofile 65535、nginx hard nofile 65535
- 检查内核参数 net.core.somaxconn(建议 ≥ 65535)和 net.ipv4.ip_local_port_range(如 1024 65535)
避免阻塞操作破坏事件驱动模型
epoll 是非阻塞 I/O 模型,一旦 worker 中出现同步阻塞行为(如访问本地磁盘日志、调用不带 timeout 的 upstream、执行耗时 lua 脚本),整个事件循环会被卡住,吞吐量断崖下跌。
- 日志写入务必用 buffer 和 flush(如 access_log /path/log main buffer=16k flush=5s)
- proxy_pass 上游务必配置 proxy_connect_timeout、proxy_read_timeout、proxy_send_timeout
- 慎用 ngx_lua 的 blocking 函数(如 os.execute、io.open),优先用 cosocket 异步接口