worker_cpu_affinity 与 irq 绑定必须协同:前者固定 nginx worker 进程到指定 cpu,后者将网卡中断(如 rx/tx)绑定至相同物理核,避免跨核缓存失效、tlb 刷新及抢占抖动;未优化时 p99 延迟可高出 2~3 倍。

worker_processes 本身不绑定 CPU,它只决定启动几个 worker 进程;真正让进程“钉”在特定核心上运行的,是 worker_cpu_affinity 指令。而操作系统中断(IRQ)的亲和力绑定——比如网卡软中断、时钟中断等——是另一个独立但关键的协同层。两者不直接等价,但必须配合,否则即使 Nginx 工作进程绑好了核,频繁的 IRQ 打断仍会导致缓存抖动、延迟升高、QPS 波动。
为什么 IRQ 绑定不能忽略
Linux 内核默认把网络中断(如 eth0 的 RX/TX、softirq)分散到所有可用 CPU 上。若 Nginx 的某个 worker 绑在 CPU 3,而该网卡中断却大量落在 CPU 0~2,那 CPU 3 上的 worker 实际要频繁跨核接收软中断处理后的数据包,引发: - L3 缓存失效与跨 NUMA 访问延迟 - TLB 刷新开销上升 - worker 进程被抢占打断,响应时间毛刺增多 实测表明,在高吞吐静态服务中,未调 IRQ 亲和力时,P99 延迟可能比优化后高出 2~3 倍。
如何查看并绑定网卡中断亲和力
先查当前中断分布:
- cat /proc/interrupts | grep -i eth —— 找出网卡对应中断号(如 45、46)
- cat /proc/irq/45/smp_affinity_list —— 查当前允许运行的 CPU 列表(如 0,1,2,3)
再绑定到与 Nginx worker 对齐的物理核心(例如你设了 worker_processes 4 并用 worker_cpu_affinity 0001 0010 0100 1000,即绑定 CPU 0/1/2/3):
- echo 0-3 > /proc/irq/45/smp_affinity_list —— 把中断限制在这 4 个核内
- 更精细做法:为每个 RX 队列单独绑定(需网卡支持多队列),如 echo 0 > /proc/irq/45/smp_affinity_list(RX queue 0 → CPU 0)、echo 1 > /proc/irq/46/smp_affinity_list(RX queue 1 → CPU 1)
与 Nginx worker 绑核的对齐原则
目标是让“请求路径”尽量在同一物理核完成:网卡收包 → 软中断处理 → epoll_wait 触发 → worker 进程读取 socket。推荐策略:
- 若用 worker_cpu_affinity auto;(Nginx ≥1.9.10),优先启用 irqbalance --banirq=eth0 并手动绑定 IRQ 到物理核,避免超线程干扰
- 四核物理机(无超线程):worker 绑 CPU 0/1/2/3 → IRQ 同样限定在 0-3,且建议按队列一对一(RX queue 0 ↔ CPU 0)
- 八核带超线程(4 物理核 × 2 线程):worker_processes 设为 4,worker_cpu_affinity 设为 0001 0010 0100 1000(即只用 core0t0, core1t0, core2t0, core3t0)→ IRQ 也只绑定到这 4 个物理核的主逻辑 CPU(编号 0/2/4/6 或 0/1/2/3,依系统编号而定)
- 容器/K8s 环境:IRQ 绑定须在宿主机侧完成,且只能绑定到容器实际可调度的 vCPU 对应的物理核范围(例如 K8s 分配 2 个 vCPU 给 Pod,对应宿主机 CPU 4 和 5,则 IRQ 只能设为 4,5)
验证是否真正协同生效
三步交叉验证:
- ps -eo pid,psr,comm | grep "nginx: worker" —— 确认每个 worker 固定在预期 CPU(PSR 列稳定)
- cat /proc/interrupts | grep "eth.*[0-9]" —— 查看各中断计数是否集中在你指定的 CPU 列上
- perf top -C 0 -p $(pgrep -f "nginx: worker" | head -1) —— 在绑定 CPU 0 的 worker 上采样,若看到大量 __softirqentry_text_start 或 net_rx_action,说明软中断仍在本核高效处理











