irqbalance 默认在多队列网卡上失效,将所有中断集中到cpu0,因其无法准确识别rss队列负载;需停用后手动绑定irq、启用rps/rfs并禁用gro/lro才能实现真正均衡。

irqbalance 默认在多队列网卡上经常失效,反而把所有中断塞给 CPU0 —— 不是配错了,而是它压根没识别到 RSS 队列负载,直接放弃均衡。真要均匀分担,得关掉它,手动绑 + 补 RPS/RFS。
为什么 irqbalance 会把所有网卡中断塞给 CPU0
它依赖 /proc/interrupts 的计数更新和 softirq 延迟反馈做负载评估,但 RSS 队列中断计数滞后、NET_RX 软中断延迟不被准确采集、或内核版本(如 4.19/5.4)中 irqbalance 对 MSI-X 多向量中断识别有缺陷,都会让它“以为”只有 CPU0 在干活。现象很典型:cat /proc/interrupts | grep eth0 显示所有 eth0-TxRx-* 行的数字全集中在第一列;watch -n1 'cat /proc/softirqs | grep NET_RX' 里只有 CPU0 的值飙升。
停用 irqbalance 后怎么安全绑定各 RSS 队列到不同 CPU
不能只停服务,必须逐个 IRQ 精确绑定,否则可能误绑系统中断或触发 NUMA 远程访问:
- 先确认网卡队列数:
grep eth0 /proc/interrupts | wc -l(比如输出 8,说明有 8 个 RSS 队列) - 查可用 CPU 列表:
cat /sys/devices/system/cpu/online,排除isolcpus或rcu_nocbs绑定的核 - 逐个写入
smp_affinity_list:echo 0 > /proc/irq/44/smp_affinity_list(假设 44 是eth0-TxRx-0的 IRQ 号)echo 1 > /proc/irq/45/smp_affinity_list(45 是eth0-TxRx-1)
……依此类推,确保每个队列对应一个独占 CPU - 验证是否生效:
cat /proc/irq/44/smp_affinity_list应返回0,且/proc/interrupts中该行数字开始在对应列增长
RPS/RFS 必须补上,否则中断分开了 softirq 还是挤在单核
单纯绑 IRQ 只控制硬中断投递,NET_RX 软中断仍可能全部在 CPU0 上执行 —— 因为上层收包路径没分流:
- 检查 RPS 是否启用:
cat /sys/class/net/eth0/queues/rx-0/rps_cpus,为空就需配置
例如 8 核:对每个 rx 队列执行echo ff > /sys/class/net/eth0/queues/rx-0/rps_cpus(十六进制掩码) - RFS 推荐开启:
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries,再为每个 rx 队列设rps_flow_cnt:echo 2048 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt - 务必关闭 GRO/LRO:
ethtool -K eth0 gro off lro off,否则大包重组会绕过 RPS,集中消耗单核 softirq
验证是否真正均衡的关键命令
别信 top 或 htop 里的 si%,它们只反映采样瞬间,容易漏掉 burst:
- 持续观察软中断分布:
watch -n1 'grep -E "NET_RX|NET_TX" /proc/softirqs',确认各 CPU 列数值同步上升,标准差 - 检查实际收包队列使用率:
ethtool -S eth0 | grep rx_queue_.*_packets,8 个队列数值应大致接近(±20% 内) - 如果仍有某核 softirq 持续偏高,大概率是 RPS 掩码没对齐队列数,或应用层 socket 没开
SO_ATTACH_REUSEPORT_CBPF导致连接哈希倾斜
最易被忽略的是:RSS 队列数 ≠ CPU 数 ≠ RPS 掩码位数。三者不对齐时,哪怕 IRQ 绑对了,RPS 也会把多个队列映射到同一个 CPU,软中断照样打满。动手前一定先跑 ethtool -l eth0 确认 Combined 值,再决定绑几个核、设几位掩码。











