本质是连接调度失衡,需排查accept_mutex配置、multi_accept开关、系统backlog、慢/长连接占用及Lua同步阻塞。

这种情况本质是连接调度失衡,不是配置写错,而是事件分发或客户端行为导致流量被“钉死”在某个 worker 上。关键要确认是不是真闲置、为什么只压一个、以及是否隐藏了慢连接或长连接问题。
先验证是否真的存在进程闲置
别只看 top 的 CPU 占用——worker 进程可能在等 I/O(比如 SSL 握手、上游响应、客户端发包慢),此时 CPU 低但 RSS 高、连接数高。正确做法是:
- 用 ps -o pid,rss,comm -p $(pgrep -P $(pgrep nginx)) | sort -k2 -nr 查每个 worker 的 RSS,看内存是否严重不均
- 用 ss -tnp | grep :80 | awk '{print $7}' | cut -d',' -f2 | cut -d'=' -f2 | sort | uniq -c | sort -nr 统计各 worker 处理的连接数,确认是否集中在单个 PID
- 打开 stub_status,观察每个 worker 的 Active connections 分布(需配合 OpenResty 或自定义日志字段)
检查连接分配机制是否失效
Nginx 默认靠 accept_mutex 和内核 socket queue 分发新连接。如果它失效,就容易出现“一核有难,八核围观”:
- 确认 accept_mutex off 是否被误开(Kubernetes 场景下合理,但裸机或旧版配置中开启反而加剧争抢)
- 检查 multi_accept on 是否启用——关掉会导致单次只收一个连接,加剧调度延迟
- 运行 cat /proc/sys/net/core/somaxconn 和 nginx -T | grep worker_connections,确保系统 backlog 不小于 worker_connections × worker_processes
排查慢连接或长连接“卡位”行为
一个 worker 被占满,未必是请求多,更可能是某些连接长期挂起:
- 用 ss -tni | grep ESTAB 看每个连接的 retrans、rto、unacked 字段,识别网络层卡顿的连接
- 查 access.log 中对应时间窗口的 $request_time 和 $upstream_response_time,若 request_time 远大于 upstream_response_time,说明卡在 client read 或 response write 阶段
- 特别关注 WebSocket、SSE、大文件下载等长连接场景——它们会持续占用 worker 连接槽位,且不触发超时释放
检查第三方模块或 Lua 脚本干扰调度
OpenResty 中的同步操作会阻塞整个事件循环,让该 worker 暂停处理新连接:
- 搜索配置中是否有 ngx.location.capture(未加 async)、io.open()、ngx.sleep(0) 等同步调用
- 临时注释所有 lua_code_cache off 的脚本,或用 lua_shared_dict 替代全局变量,避免锁竞争
- 启用 error_log /var/log/nginx/error.log debug,抓取特定 worker 的事件循环卡点(注意日志量巨大,仅短时开启)


















