net_rx softirq高导致单核CPU打满,本质是网络接收软中断未分散至多核:需验证网卡多队列启用状态、irqbalance运行及策略有效性、IRQ手动绑定合理性,并调优RX队列长度、GRO/LRO及softnet_stat参数。

.net_rx softirq 高导致单核 CPU 打满,本质是网络接收软中断集中在某个 CPU 核上处理,而网卡多队列 + irqbalance 本应分摊负载,但配置不当或机制未生效时就会失效。
确认网卡是否真正启用了多队列
很多网卡默认只启用单个 RX 队列,即使硬件支持多队列,驱动没打开或固件限制也会退化为单队列。需逐层验证:
- 查物理队列数:ethtool -l eth0(看 Current hardware settings 下的 RX 队列数,非 Supported max)
- 查当前启用队列数:cat /sys/class/net/eth0/device/sriov_numvfs(仅 SR-IOV 场景)或更通用的:ls /sys/class/net/eth0/device/msi_irqs/(每个 IRQ 对应一个队列)
- 查驱动是否启用多队列:grep "rx.*queue" /proc/interrupts | grep eth0,应看到多个形如 eth0-rx-0、eth0-rx-1 的条目;若只有 eth0(无后缀),说明仍是单队列中断绑定
检查 irqbalance 是否运行且策略合理
irqbalance 不只是“开了就行”,它可能因配置、服务状态或内核参数被绕过:
- 确认服务活跃:systemctl status irqbalance,且输出含 active (running)
- 检查是否被禁用:查看 /proc/sys/kernel/irqbalance(值为 1 表示启用),或 cat /etc/default/irqbalance 中是否设了 ENABLED=0
- 避免干扰策略:若使用 --banirq 或 --hintpolicy=ignore 等参数,可能导致网卡 IRQ 被固定不动;建议用默认策略或显式指定:--hintpolicy=restrict
- 观察实际分布:watch -n1 'grep eth0 /proc/interrupts',看各 RX 队列 IRQ 是否分散到不同 CPU;若长期只在 CPU0 触发,说明 irqbalance 没生效或被覆盖
手动绑定 IRQ 到 CPU(当 irqbalance 不可靠时)
某些场景(如实时性要求高、irqbalance 与内核版本兼容问题)推荐跳过 irqbalance,直接静态绑定:
- 查网卡各 RX 队列对应的 IRQ 号:grep eth0-rx /proc/interrupts | awk '{print $1}' | tr -d ':'
- 将 IRQ 绑定到特定 CPU 掩码(如绑到 CPU1~CPU7):echo 00fe > /proc/irq/[IRQ_NUM]/smp_affinity_list(十六进制掩码,00fe = CPU1~7)
- 注意:需确保目标 CPU 不承担其他高负载任务(如应用进程、ksoftirqd),否则仍会打满;可配合 taskset 将业务进程绑到其余核
- 持久化:写入 systemd service 或网络脚本,在网卡 up 后执行(因 IRQ 号可能随重启变化,建议用 udev rule + shell 脚本动态识别)
补充调优:降低 net_rx softirq 压力本身
分流只是治标,还需减少单次软中断要处理的数据量:
- 增大 RX 队列长度:ethtool -G eth0 rx 4096(防丢包,也缓解突发冲击)
- 启用 GRO/LRO(谨慎):ethtool -K eth0 gro on,合并小包减少中断次数;但会增加延迟和 CPU 解包开销,高吞吐低延迟场景慎用
- 检查是否被 NAPI polling 阻塞:若 cat /proc/net/softnet_stat 第二列(dropped)持续增长,说明 softirq 处理不过来,需调大 net.core.netdev_budget(默认300)或优化协议栈路径










