你的 Nginx worker 进程数,是不是还卡在 auto 上没动过?

你有没有试过:流量一上来,服务器就变卡,top 里 CPU 利用率忽高忽低,Nginx 日志里开始刷 accept() failed (24: Too many open files)?调了 keepalive_timeout、改了 gzip,结果还是治标不治本——可能问题就藏在那行被你忽略的 worker_processes auto; 里。

worker 进程数设置的核心原则是什么?

一句话:别让它比 CPU 核心数多,也别让它比核心数少太多。

Nginx 的每个 worker 进程,同一时间只能在一个 CPU 核心上跑。设少了,核心空转;设多了,系统忙着来回切换进程,反而耽误干活。

worker_processes auto; 是个好起点——它会读取 /proc/cpuinfo,自动设成逻辑核心数。但这个“自动”,只认得 CPU,不认得你服务器上还蹲着 MySQL、PHP-FPM、甚至一个常驻的 Python 后台任务。它们都在抢同一个 CPU 资源。

比如你有 8 核,但 MySQL 经常吃掉 2~3 个核的算力,这时候还让 Nginx 开 8 个 worker,等于硬塞两拨人挤一条窄道,谁也跑不快。

如何根据你的服务器情况做调整?

先别急着改配置,打开终端,敲两行命令摸清底细:

nproc                 # 看总共有几个逻辑核
ps aux --sort=-%cpu | head -5   # 看现在谁在 CPU 上最活跃

然后问自己一个问题:这台机器是专干 Nginx 的,还是顺带跑数据库、缓存、API 的?

真实案例:一台 8 核的线上服务器,跑着 WordPress(PHP-FPM + MySQL)+ Nginx。一开始 worker_processes 8;,高峰期 htop 里能看到 3 个核心 CPU 接近 100%,剩下 5 个却只有 20% 利用率,请求延迟直接翻倍。

后来改成 worker_processes 6;,再配上 worker_cpu_affinity 00000011 00000101 00001001 ...(把 6 个 worker 绑定到前 6 个核心),MySQL 和 PHP-FPM 自然落到剩下两个核上。上下文切换少了,响应时间稳定了不少,高峰期也不再频繁超时。

是不是进程数越多,性能就一定越好?

不是。这是很多人踩过的坑。

每个 worker 进程本身要占内存,还要参与系统调度。你给一台 4 核机器配 worker_processes 32;,操作系统光是决定“接下来让哪个 worker 上 CPU”就要花掉大量时间,真正处理 HTTP 请求的时间反而被压缩了。

性能提升不是直线上升的。从 1 到 4 个 worker(对应 4 核),效果通常很明显;但从 4 涨到 8,收益可能微乎其微;再涨到 16,说不定连 nginx -t 都开始报 warning,日志里全是 fork() failed

你要找的不是一个最大值,而是一个“够用、稳当、不打架”的数字。

如何验证你的设置是否合理?

改完别扔那儿不管。打开 Nginx 状态页,看一眼真实负载:

确保 ngx_http_stub_status_module 已启用(主流发行版编译时默认带上),然后在 nginx.conf 的 server 块里加:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

重载后访问 http://localhost/nginx_status,重点盯住这一行:

Active connections: 291
server accepts handled requests: 123456 123456 789012
Reading: 6 Writing: 3 Waiting: 282
  • Waiting 数长期接近 worker_connections,说明连接排队严重;
  • 但同时 top 里 CPU 利用率才 40%,那瓶颈大概率不在 CPU,可能是磁盘 IO 或后端应用拖慢了响应;
  • 如果 Waiting 很低,CPU 却已飙到 90%+,且 htop 显示某些核心满载、其他核心闲置——那就该调 worker_processes 了。

高并发场景下,还需要搭配调整哪些参数?

worker_processes 只是半张牌,另一半是 worker_connections

理论最大并发 = worker_processes × worker_connections,但系统不会无条件配合你。Linux 默认限制每个进程最多打开 1024 个文件描述符(包括 socket 连接),超过就报错 Too many open files

所以三件事得一起做:

  1. 查当前限制:ulimit -n
  2. 查系统总上限:cat /proc/sys/fs/file-max
  3. nginx.conf 里补上:
    worker_rlimit_nofile 65535;
    events {
        worker_connections 65535;
    }
    

真实踩坑记录:一个内部管理后台用了长轮询,worker_connections 设到 20000,但忘了改 ulimit。上线当天下午,所有接口开始随机 502,错误日志里全是 open() failed (24: Too many open files)。补上 limits.confworker_rlimit_nofile,重启后立刻恢复正常。

今天下班前,你能做的具体操作是什么?

别等“下次大版本重构”,现在就打开终端,按顺序走一遍:

  1. 执行 nproc,记下数字(比如输出是 8);
  2. 执行 grep worker_processes /etc/nginx/nginx.conf,看看现在是 auto 还是某个固定值;
  3. 执行 top,按 P 按 CPU 排序,观察前 3 名常驻进程(比如 mysqld 占 40%,php-fpm 占 25%);
  4. 心算预留:8 核 − 2 核(给数据库)− 1 核(给 PHP)= 5 → 把 worker_processes 改成 5
  5. 执行 grep worker_connections /etc/nginx/nginx.confulimit -n 对比,如果后者 ≤ 前者,马上编辑 /etc/security/limits.conf,加上:
nginx soft nofile 65535
nginx hard nofile 65535
  1. 最后,执行 sudo nginx -s reload —— 不用停服务,配置立刻生效。

做完这六步,你就已经甩开 80% 还在用默认配置的同行了。后续要不要开 worker_cpu_affinity、要不要调 epoll 参数,都建立在这个干净、合理的基础上。