网络软中断跑满单个核,你会如何调整 RPS 网卡多队列与亲和性
解读
- 场景定位:生产或压测环境出现
si软中断飙高,且仅集中在 CPU0(或某一颗逻辑核),导致该核 100 % 占用,业务线程因拿不到 CPU 而 RT 抖动、吞吐下降。 - 根因判断:
- 单队列网卡或虽有多队列但队列数 < CPU 核数,导致所有报文中断由一颗核处理;
- 硬中断已均衡,但内核协议栈后续处理(RPS/RFS)未开启或未正确绑核,仍回落到 CPU0;
- 业务线程与软中断落在同一核,互相抢占。
- 调优目标:让“中断+协议栈+业务”三层负载均摊到多核,且避免跨 NUMA 访存,最终使
si单核跑满现象消失,系统吞吐线性提升,CPU 利用率各核均衡 < 80 %。
知识点
- 中断路径:
硬中断(IRQ)(NIC 触发)→ 软中断(NET_RX)→ 协议栈 → socket → 业务线程。 - 网卡多队列(RSS,Receive Side Scaling):
硬件依据 hash(IP、端口)把报文散列到多个 RX 队列,每队列绑定不同 CPU,硬中断即可分散。 - RPS(Receive Packet Steering):
软件模拟 RSS,在单队列网卡或队列数不足时,由软中断阶段把报文再次散列到多个 CPU 的 backlog 队列处理。 - RFS(Receive Flow Steering):
在 RPS 基础上,把同一五元组流定向到“运行该流应用线程”的 CPU,提高缓存命中率。 - 中断亲和性(irqbalance、smp_affinity):
控制硬中断落在哪些核;关闭 irqbalance 可手动精准绑核。 - 调度亲和性(taskset、sched_setaffinity、cgroup cpuset):
把业务线程与软中断处理核隔离,避免抢占。 - NUMA 亲和:
网卡、内存、CPU 同属一个 node,减少跨 node 访存延迟。 - 观测工具:
top/mpstat -P ALL 1看 si 分布;cat /proc/interrupts看 IRQ 分布;perf top -g看软中断热点;ethtool -l/-x/-S查看队列、hash、计数;cat /proc/softirqs看 NET_RX 分布。
答案
-
确认硬件能力
ethtool -l eth0查看网卡最大队列数与当前队列数;若最大>1 且当前=1,先开启多队列:
ethtool -L eth0 combined N(N 取 CPU 核数或≤最大队列数)。 -
硬中断绑核
- 关闭自动均衡:
systemctl stop irqbalance;systemctl disable irqbalance - 计算 NUMA node:
cat /sys/class/net/eth0/device/numa_node - 把各队列 IRQ 平均绑定到同一 node 的不同核,避开 CPU0:
echo 00000002 > /proc/irq/24/smp_affinity(示例把 IRQ24 绑到 CPU1,十六进制位掩码)。
- 关闭自动均衡:
-
启用并调优 RPS
- 计算掩码:期望参与软中断的核掩码,如 8 核机器 CPU1-7 参与,掩码为 0xFE。
- 设置队列级 RPS:
echo FE > /sys/class/net/eth0/queues/rx-0/rps_cpus
若已开多队列,对每个 rx-N 目录都写相同掩码,实现软中断继续分核。 - 调大 rps_flow_cnt 与 rps_sock_flow_entries:
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
保证五元组 hash 表不冲突。
-
启用 RFS(可选)
内核版本≥2.6.35 默认编译了 RFS,只需保证rps_sock_flow_entries足够大即可;
若业务流<队列数,可进一步把rps_flow_cnt按流数调小,节省内存。 -
隔离业务线程
- 用
taskset -c 4-7 java -jar app.jar把应用绑到 NUMA node0 的后半部分核; - 或在 systemd service 里加
CPUAffinity=4-7; - 保证软中断核(1-3)与应用核(4-7)不重叠,减少上下文切换。
- 用
-
验证
mpstat -P ALL 1观察 si 列各核均匀且总占比下降;cat /proc/softirqs | grep NET_RX看计数在各核增量均衡;- 压测同样并发,TPS 提升、RT P99 下降、CPU0 不再跑满。
-
兜底策略
若老旧内核或云主机无法改硬中断,可仅依赖 RPS+RFS,也能把软中断分散到多核,效果略逊于 RSS,但可解决单核跑满问题。
拓展思考
-
容器场景:
Kubernetes 下网卡多队列仍受宿主机控制,但容器内看到的 CPU 集合由 cpuset 限制;
需在宿主机层完成 IRQ/RPS 绑核,再通过cpuManagerPolicy=static把业务容器绑到专属核,避免与软中断核冲突。 -
发送方向优化:
若瓶颈在 TX 软中断(如反向代理上行流量大),可开启 XPS(Transmit Packet Steering):
echo 0xFE > /sys/class/net/eth0/queues/tx-0/xps_cpus,把发送负载也分散。 -
新内核技术:
- aRFS(hardware-accelerated RFS): 网卡驱动与内核协同,把 RFS 提示直接写进硬件过滤器,实现零开销流定向;
- XDP + AF_XDP:在用户态完成收包,绕过软中断,适合高频小包场景;
- IRQ 合并与自适应中断调节:
ethtool -C eth0 adaptive-rx on减少中断风暴。
-
云厂商差异:
阿里云增强型实例已默认开启最大队列数并自动绑核,但掩码可能仍包含 CPU0;
腾讯云黑石裸金属允许自定义 IRQ 亲和性,需手动调优;
AWS ENA 驱动推荐ethtool -L combined开到最大,并关闭 irqbalance,再配 RPS。 -
监控闭环:
把/proc/softirqs、/proc/interrupts指标接入 Prometheus + Grafana,设置“单核 NET_RX 增量>80 % 持续 1 min”告警,实现调优效果可观测、回归可发现。