资讯动态

Linux Nginx 怎么配置 worker_processes 优化多核 CPU 性能

发布时间:2026/10/6 16:18:22 来源:尧图企业网站定制
前言一台 8 核 16G 的服务器压测时top里只有一颗 CPU 跑满 100%其余 7 颗几乎闲置QPS 卡在某个数字上再也上不去或者反过来CPU 倒是都用上了但ss -s显示大量请求在排队error.log里偶发worker_connections are not enough。这两种现象几乎都指向同一处配置worker_processes及其周边参数没有按机器的核数来配。Nginx 的并发模型是「一个 master 进程 N 个 worker 进程」master 只负责读配置、管信号、拉起 worker真正处理连接的是 worker。worker 进程数与 CPU 核数的关系直接决定了这些进程能不能被内核并行调度到不同的核上。默认值worker_processes 1意味着无论机器有多少核都只有一个进程在处理请求。本文基于 RHEL 9 / nginx 1.24nginx.conf位于/etc/nginx/nginx.conf包由 nginx.org 官方仓库安装服务名nginx。Debian/Ubuntu 上路径同样是/etc/nginx/nginx.confuser默认是www-data而不是nginx其余配置写法一致。文中所有片段都可直接复制后nginx -t校验。一、worker_processes 控制什么worker_processes是main上下文也叫全局块指令只能出现在nginx.conf最外层不能写进events或http块。它的取值取值含义适用场景数字如4固定拉起 4 个 worker容器内核数受限、需要精确控制内存占用auto等于nproc返回的 CPU 核数绝大多数场景的推荐值auto从 nginx 1.3.8 / 1.2.5 起可用它读的是操作系统报告的核数sysconf(_SC_NPROCESSORS_ONLN)。为什么是「一核一 worker」而不是「越多越好」worker 之间没有共享内存的请求队列除共享内存区 zone 外每个 worker 独立accept新连接、独立跑事件循环。多出来的 worker 只能抢同一批连接抢不到的就空转反而增加上下文切换和accept竞争。每个 worker 是单线程事件驱动epoll/kqueue一个 worker 在任一时刻只跑在一个核上。所以 worker 数少于核数就有核闲着多于核数就有 worker 在排队等 CPU。内存按 worker 复制。每个 worker 的常驻内存大致在几 MB 到几十 MB 量级具体取决于模块和worker_connections分配的事件结构体所以在内存紧张的机器上把 worker 数开到核数以上并不划算。一个特殊情况如果负载里有大量阻塞型操作比如同步访问磁盘、调用了阻塞的第三方模块或者工作负载以 SSL/TLS 握手为主适度超配auto的 1.52 倍有时能掩盖单核上的阻塞停顿。不要凭直觉超配先用ps观察每个 worker 的 CPU 占用是否均衡。查看实际起来的 worker 数量ps -eo pid,ppid,psr,pcpu,comm | grep -E nginx: (master|worker) | sort -k2 -npsr列是该进程当前所在的 CPU 编号。加一行sort只是为了好看验证是否均匀分布在 0..N-1 上。二、worker_connections 与真实并发上限worker_processes只决定「有几个干活的」真正决定「能同时扛多少连接」的是events块里的worker_connections。这两个值经常被一起配错。events {worker_connections 10240;multi_accept on;}理论并发连接数 ≈worker_processes×worker_connections。但有两点必须记住对反向代理场景Nginx 同时持有「客户端连接」和「到上游的连接」两条一条客户端请求要占掉 2 个连接额度。所以实际能服务的客户端数大约是乘积的一半。如果开了keepaliveHTTP 长连接连接在空闲期也一直占着额度不会立即释放。multi_accept on让 worker 一次事件循环里尽可能多地把新连接全accept掉而不是一次只取一个。在高并发新建连接场景下能减少 epoll 唤醒次数属于低风险选项。另外每一个连接还需要一个文件描述符所以worker_connections开大之后必须同步放开 fd 上限见第四节的实战配置。三、CPU 亲和性与进程优先级默认情况下 Linux 调度器会把 worker 在核之间来回迁移这会导致 CPU cacheL1/L2 上的热点数据、连接结构体反复失效。worker_cpu_affinity把每个 worker 绑定到固定的核上worker_processes 4;worker_cpu_affinity 0001 0010 0100 1000;掩码是十六进制的 CPU 位图位从右往左数0001表示第 0 号 CPU0010表示第 1 号 CPU。掩码个数必须等于worker_processes否则nginx -t直接报invalid number of arguments。8 核机器要写 8 个掩码形如00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000。嫌手写掩码麻烦的话从 nginx 1.9.10 起可以直接worker_processes auto;worker_cpu_affinity auto;auto会按核数自动生成掩码。如果只想让 Nginx 用其中几颗核也可以写0001 0010 0100 1000配worker_processes 4把剩下 4 颗留给数据库或其它服务。worker_priority用来调 worker 的 nice 值范围-20到19负数优先级更高但需要 root 权限启动 masterworker_priority -10;除非系统里还有别的争抢 CPU 的进程否则一般不动这一项。四、实战一份多核可用配置 系统侧配套以下基于 RHEL 9 / nginx 1.24/etc/nginx/nginx.conf顶部结构user nginx;worker_processes auto;worker_cpu_affinity auto;worker_rlimit_nofile 65535;worker_shutdown_timeout 10s;error_log /var/log/nginx/error.log warn;pid /run/nginx.pid;events {worker_connections 10240;multi_accept on;}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for;access_log /var/log/nginx/access.log main;sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 65;keepalive_requests 1000;include /etc/nginx/conf.d/*.conf;}worker_rlimit_nofile让 worker 自己调用setrlimit抬高 fd 上限但它不能突破 systemd 给服务设的硬上限。用 systemd 托管的话还要配 unit只在需要超过默认值时改# /etc/systemd/system/nginx.service.d/limits.conf[Service]LimitNOFILE65535sudo systemctl daemon-reloadsudo systemctl restart nginx# 确认 worker 实际拿到的 fd 上限sudo cat /proc/$(pgrep -o -f nginx: worker)/limits | grep -i open files# 校验配置语法再平滑重载sudo nginx -t sudo systemctl reload nginx验证生效# 1. worker 数量是否等于核数echo cpu: $(nproc)echo worker: $(pgrep -c -f nginx: worker)# 2. worker 是否分散在不同核上ps -eo pid,psr,comm | grep nginx: worker# 3. 单机自测ab 来自 httpd-tools 包RHEL: sudo dnf install httpd-toolsab -n 20000 -c 200 -k http://127.0.0.1:80/上面的ab命令请在你自己的机器上跑对比改配置前后的Requests per second和top里的 CPU 分布。不同硬件、不同业务的结果差异极大任何具体的提升百分比都不能跨环境照搬。常见坑点❌ 在 2 核 VPS 上写死worker_processes 8;内存翻倍且上下文切换变多✅ 一律用worker_processes auto;需要压测试对比时再临时改数字❌ 只把worker_processes调大events块里还是默认的worker_connections 512;并发上不去✅ 同步调大worker_connections并按需同步worker_rlimit_nofile与 systemd 的LimitNOFILE❌ 写成worker_cpu_affinity 0001 0010;而worker_processes是 4掩码数量不匹配✅ 掩码个数必须等于 worker 数或直接用worker_cpu_affinity auto;改完必须nginx -t❌ 把worker_connections写进http块或main上下文报directive is not allowed here✅worker_connections、multi_accept、use属于events块worker_processes、worker_rlimit_nofile、worker_cpu_affinity属于main上下文❌ 先systemctl reload nginx再看日志结果配置写错reload 失败但旧进程还在跑以为改生效了✅ 永远nginx -t通过后再 reloadreload 后看error.log有无emerg/alert❌ 用taskset -c 0 systemctl start nginx绑定了 master又配了worker_cpu_affinity auto两套亲和性叠加worker 被挤在错误的核上✅ 二选一要么用 Nginx 自己的worker_cpu_affinity要么用 systemd 的CPUAffinity不要同时用taskset包一层❌ 在 Docker 里跑worker_processes auto;它读到的是宿主机的核数除非容器用 cpuset 限制worker 数远超容器实际可用 CPU✅ 容器里显式写数字或用--cpuset-cpus限制不同内核对nproc是否反映 cgroup 配额的行为不一致以实测为准❌ 看到 worker 数对了就不再管实际上multi_accept默认off高并发建连时 epoll 唤醒次数偏多✅ 建连密集的服务打开multi_accept on;纯长连接的服务可以不开总结指令作用域推荐值关键点worker_processesmainauto等于 CPU 核数不是越大越好worker_cpu_affinitymainauto掩码个数必须等于 worker 数worker_rlimit_nofilemain大于worker_connections受 systemdLimitNOFILE硬限制worker_prioritymain默认 0负数需 rootworker_connectionsevents按并发量定反代场景一条请求吃 2 个连接multi_accepteventson建连密集场景收益明显调优的顺序应该是先确认worker_processes与核数匹配再根据业务并发量算worker_connections最后放开 fd 上限并配合worker_cpu_affinity减少迁移。改完一定用nginx -t校验、用ps -eo psr验证分布、用自己的压测脚本验证效果——别人的性能数字对你没有意义。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑