Nginx架构核心是单worker进程+epoll/kqueue事件循环实现高并发,调优聚焦事件分发公平性、文件描述符上限及内核/用户态数据搬运效率;需正确配置worker_cpu_affinity、worker_rlimit_nofile、accept_mutex、multi_accept、sendfile等参数,并注意location匹配与proxy_pass路径替换逻辑。
从多路复用底层出发看Nginx架构,核心就一句话:它靠一个worker进程+epoll/kqueue事件循环,非阻塞地轮询成千上万个连接。所有调优和踩坑,本质都是围绕“事件分发是否公平”“文件描述符是否够用”“内核与用户态数据搬运是否冗余”这三件事展开。
很多人设worker_processes auto就以为万事大吉,但没配worker_cpu_affinity时,Linux调度器可能把所有worker都挤在同一个CPU核上,导致该核满载、其余核空转。尤其在高并发短连接场景下,上下文切换激增,延迟飙升。
worker_cpu_affinity auto;(Nginx 1.12.2+支持)或手动写成worker_cpu_affinity 0001 0010 0100 1000;
lscpu | grep "CPU(s)"确认物理核数,避免worker数超过物理核(超线程可适当增加,但不宜翻倍)worker_rlimit_nofile时,即使worker_connections设再高,也会被系统ulimit卡死,报too many open files
epoll本身高效,但Nginx怎么用它,决定实际吞吐。常见错误是把关键开关关反了,或者参数没对齐系统能力。
accept_mutex on在现代高版本内核(4.5+)反而降低性能,应设为off;它本意是防止“惊群”,但现已被内核优化接管multi_accept on必须配套worker_connections足够大,否则一次收太多连接却处理不过来,堆积在队列里触发超时use epoll不能只写在配置里——要确认运行环境:CentOS 7+/Ubuntu 16.04+默认支持,但容器中若用极简镜像(如alpine+musl),可能无epoll,需回退到poll并接受性能折损sendfile、tcp_nopush、tcp_nodelay这三个指令,表面是HTTP模块配置,实则深度耦合内核TCP协议栈行为。乱配会导致小包泛滥或大包延迟。
sendfile on开启后,Nginx跳过用户态拷贝,但若后端是动态内容(如PHP-FPM返回的HTML),它不生效——此时必须依赖tcp_nopush on来攒包tcp_nopush on和tcp_nodelay on看似矛盾,实为互补:nopush等完整响应头+body凑满MSS再发;nodelay则对keepalive期间的小心跳、WebSocket ping帧立即发出,不等待ssl_buffer_size 4k比默认的16k更适配移动端弱网,避免TLS record过大导致重传放大这不是架构层问题,却是由事件驱动模型放大的典型连锁故障:一个请求因location匹配错,被错误路由,接着proxy_pass路径拼接出错,最终触发上游404或502,而日志里只显示“upstream timed out”,排查陷入迷宫。
location /api + proxy_pass http://backend → 后端收到/api/xxx(原样转发)location /api + proxy_pass http://backend/ → 后端收到/xxx(/api被剥离)——这个斜杠是隐性重写开关~ /api/vd+永远优先于前缀匹配/api,想让特定路径避开正则,得用^~ /api/internal强制前缀截断proxy_pass,DNS解析回环导致server_name匹配错位,请求直接落到前端server块——必须用upstream指向127.0.0.1:port