先说一个核心判断:要精准排查网卡中断绑定,直接查看 /proc/irq/*/smp_affinity_list 是最可靠的方式,不要被 top 或 mpstat 显示的单个 CPU 高负载所迷惑——那些工具只能告诉你哪个核在忙,却无法说明这个核究竟绑定了哪个中断。
如何快速定位网卡对应的 IRQ 编号
网卡的中断号不能靠猜测,必须从 /proc/interrupts 中获取。具体操作并不复杂:
- 先用
nmcli device status或ip -br link show确认当前的有效网卡名称,例如enp1s0f0或ens33。 - 接着运行
grep -i "enp1s0f0" /proc/interrupts,将名称替换为你的网卡名。输出类似:
42: 1234567 0 0 0 890123 0 0 0 IR-PCI-MSI 32768-edge enp1s0f0-rx-0
第一列的42就是 IRQ 编号。如果末尾带有-rx-或-tx-后缀,说明已启用多队列,每个后缀代表一个独立的中断。 - 如果
grep没有找到结果,可以尝试用驱动名称搜索:先执行ethtool -i enp1s0f0 | grep driver获取驱动名(如i40e或mlx5_core),再运行grep i40e /proc/interrupts。
如何确认当前 IRQ 绑定到了哪些 CPU
获取 IRQ 编号后,有两个关键文件需要同时核查,缺一不可:
cat /proc/irq/42/smp_affinity_list:显示的是你写入的亲和性配置,输出为十进制的 CPU 编号列表。例如0,2,4,6表示该中断允许在这些 CPU 上运行;如果仅输出0,则代表硬绑定到 CPU 0——这是单核瓶颈的直接证据。cat /proc/irq/42/effective_affinity:显示内核实际生效的绑定情况。如果该值与smp_affinity_list不一致,很可能是irqbalance在后台自动调整。- 同时建议检查
systemctl is-active irqbalance,若返回active,操作前务必执行sudo systemctl stop irqbalance。
为什么修改了 smp_affinity_list 却没有生效
这是一个典型问题。通常不是权限或路径错误,而是被以下三个容易忽略的细节所导致:
- 目标 CPU 已被内核隔离:执行
cat /proc/cmdline,如果看到isolcpus=1,2,则不要将绑定写入 CPU 1 或 2,否则写入会静默失败甚至触发警告。 - 误用了
smp_affinity(十六进制掩码):x86 平台为 64 位,ARM 可能更宽,掩码长度错一位就容易将所有绑定分配到 CPU 0。相比之下,smp_affinity_list是更易读的十进制列表,使用更为安全。 - 驱动不支持
smp_affinity_list:某些驱动(如mlx5_core)只识别smp_affinity,但写入前必须先确认位宽。稳妥的做法是先尝试smp_affinity_list,失败后再查阅驱动文档。
网卡未开启多队列时,查看中断绑定意义有限
如果 ethtool -l enp1s0f0 显示 Combined: 1,说明硬件只配置了 1 个接收队列。在这种情况下,无论如何调整 smp_affinity_list,也只有一个 IRQ 号可供绑定,所有网络包最终仍会集中到同一个中断上下文中。
此时正确的做法不是调整绑定,而是:
- 先启用多队列:
sudo ethtool -l enp1s0f0 combined 4(通常设置为 CPU 核数的一半或匹配 NUMA 节点)。 - 再确认网卡是否支持 RPS:
ls /sys/class/net/enp1s0f0/queues/rx-*,若能见到多个rx-*目录才表示队列已激活。 - 最后对每个
rx-0、rx-1对应的 IRQ 分别绑定到不同的 CPU 上。
中断绑定并非万能开关。它是多队列、NUMA 对齐以及停用 irqbalance 三者协同才能发挥作用的结果。如果遗漏其中任意一环,你所看到的都只是表象。
