如何调整网卡中断亲和性来优化多核CPU性能?

来源:我的博客作者:马来西亚程序员头衔:程序员
导读:本期聚焦于马来西亚程序员创作的《如何调整网卡中断亲和性来优化多核CPU性能?》,敬请观看详情。网卡在高负载场景下频繁触发硬中断,如果所有中断都挤在CPU0上处理,很容易造成单核瓶颈,拖慢整机网络吞吐。中断亲和性机制允许把特定网卡的IRQ号绑定到指定的CPU核心,让中断处理均匀分散,避免争抢。本文从/proc/irq目录的smp_affinity和smp_affinity_list入手,演示如何查看当前中断分布、计算CPU掩码、使用脚本批量绑定队列中断,并说明irqbalance服务对绑定结果的覆盖风险。同时对比单队列与多队列网卡的差异,给出关闭irqbalance、持久化配置以及验证效果的具体步骤,帮助你在高并发网关或服务器上获得更稳定的网络性能。

网卡收到数据包后,需要通过硬中断通知CPU来处理。默认情况下,很多中断请求都落在CPU0上,这在低负载时没有明显问题,但一旦流量上来,CPU0可能被软中断和硬中断占满,其他核心却处于空闲状态。要解决这个问题,就需要调整中断亲和性,把不同的IRQ处理任务分配到不同的CPU核心上。

如何调整网卡中断亲和性来优化多核CPU性能?

查看当前中断分布与亲和性设置

在动手调整之前,先要弄清楚系统里每个中断当前由哪个核心处理。Linux把所有硬件中断的信息暴露在/proc/interrupts文件中,每一行代表一个IRQ,每一列对应一个CPU核心,数字表示该核心处理该中断的累计次数。

执行cat /proc/interrupts可以看到类似下面的输出。对于网卡,通常以eth0、ens33之类的设备名作为标识,后面的数字就是中断号。如果某个核心的计数远远高于其他核心,就说明中断集中在该核心上,存在优化空间。多队列网卡会为每个队列分配独立的IRQ,常见名称如eth0-TxRx-0、eth0-TxRx-1等。

cat /proc/interrupts
            CPU0       CPU1       CPU2       CPU3
  0:         34          0          0          0   IO-APIC   2-edge      timer
  8:          1          0          0          0   IO-APIC   8-edge      rtc0
 16:      33421          0          0          0   IO-APIC  16-fasteoi   ehci_hcd:usb1
 24:    1023481         12          9         11   PCI-MSI 524288-edge      eth0-TxRx-0
 25:         12    1203948         10          8   PCI-MSI 524289-edge      eth0-TxRx-1
 26:          9          8    1102832         13   PCI-MSI 524290-edge      eth0-TxRx-2
 27:         11         10          9    1293842   PCI-MSI 524291-edge      eth0-TxRx-3

每个IRQ对应的亲和性存放在/proc/irq/中断号/smp_affinity和/proc/irq/中断号/smp_affinity_list两个文件中。smp_affinity用十六进制位掩码表示允许处理该中断的CPU集合,smp_affinity_list用十进制列表表示,例如0-3代表CPU0到CPU3都可以处理。查看IRQ 24的当前设置:

cat /proc/irq/24/smp_affinity
cat /proc/irq/24/smp_affinity_list

如果smp_affinity显示为ffffffff,说明所有核心都允许处理该中断;如果显示为00000001,说明只有CPU0可以处理。在调整之前,记录这些原始值是个好习惯,方便回滚。

计算CPU掩码并绑定中断到指定核心

把IRQ绑定到特定核心需要计算十六进制掩码。掩码的每一位对应一个CPU,从右往左分别是CPU0、CPU1、CPU2……例如只允许CPU2处理中断,掩码是二进制0100,换算成十六进制为4;允许CPU0和CPU3处理,掩码是二进制1001,换算成十六进制为9。

对于较新的内核,可以直接使用smp_affinity_list文件,用更直观的十进制核心号或范围来设置,省去手动换算的麻烦。例如把IRQ 24绑定到CPU2,可以执行:

echo 2 > /proc/irq/24/smp_affinity_list
# 或者使用十六进制掩码
echo 4 > /proc/irq/24/smp_affinity

多队列网卡一般有多个IRQ,建议把每个队列中断依次绑定到不同核心,让流量处理均匀分布。假设一台4核机器上有4个队列中断,IRQ号分别为24、25、26、27,可以这样操作:

echo 0 > /proc/irq/24/smp_affinity_list
echo 1 > /proc/irq/25/smp_affinity_list
echo 2 > /proc/irq/26/smp_affinity_list
echo 3 > /proc/irq/27/smp_affinity_list

设置后再次查看/proc/interrupts,运行一段时间后各核心的中断计数应该趋于均衡。需要注意的是,如果网卡开启了RSS(接收端缩放)或RPS(接收包导向),中断虽然绑定在固定核心,但实际数据处理可能被软中断分发到其他核心,这是正常的,不影响硬中断的优化效果。

处理irqbalance服务与持久化配置

很多发行版默认开启了irqbalance服务,它会根据系统负载动态调整中断亲和性,可能把你手动设置的绑定关系覆盖掉。如果希望中断绑定固定不变,需要先停止并禁用irqbalance。在systemd系统中执行:

systemctl stop irqbalance
systemctl disable irqbalance

要确认irqbalance是否真的在干扰,可以设置绑定后等待几秒钟,再次查看smp_affinity_list是否被改变。如果被改回默认值,说明服务还在运行。对于CentOS 7/8、Ubuntu 16.04及之后的版本,都可以用上面的systemctl命令管理。个别老系统可能使用service irqbalance stop来停止。

手动通过echo写入设置的方式在重启后会丢失,需要把命令写入启动脚本。推荐使用rc.local或者systemd的service单元来持久化。也可以把绑定逻辑写成一个shell脚本,放在/etc/rc.d/rc.local中,并给脚本添加执行权限。注意要先确定IRQ号在不同重启后保持不变,对于PCIe网卡通常是稳定的,但USB网卡可能会变化,建议在脚本里动态获取IRQ号。

#!/bin/bash
# 持久化网卡中断绑定
# 获取eth0所有队列的IRQ号
irqs=$(grep eth0 /proc/interrupts | awk -F: '{print $1}')
cpu=0
for irq in $irqs; do
  echo $cpu > /proc/irq/$irq/smp_affinity_list
  cpu=$((cpu + 1))
done

对于使用NetworkManager的系统,也可以在网卡启动后的dispatcher脚本中执行绑定,这样在网卡重新加载后设置依然生效。不过无论用哪种方式,都要保证关闭irqbalance,否则所有持久化努力都可能被覆盖。

验证优化效果与注意事项

绑定完成后,需要通过实际流量测试来验证效果。可以使用iperf3打满网卡带宽,同时观察/proc/interrupts和top命令中的%si(软中断占用率)。如果中断均匀分布在各个核心,且单核软中断占用率下降,说明调整有效。也可以使用mpstat -P ALL 1命令实时查看每个核心的软中断情况。

调整中断亲和性时,不要把某个IRQ绑定到已经被其他高负载任务长期占用的核心上。例如CPU0通常还承担定时器、调度器等工作,把网卡中断绑定到CPU0并不是最优选择。对于NUMA架构的服务器,还要考虑网卡所在的NUMA节点,尽量把中断绑定到同一节点内的CPU,避免跨节点内存访问带来的延迟。

单队列网卡只有一个IRQ,无法像多队列那样把中断分散到多个核心。不过可以配合RPS技术,通过软件方式把数据包处理分散到多个核心,弥补单队列的不足。RPS的配置在/sys/class/net/eth0/queues/rx-0/rps_cpus文件中,同样是十六进制掩码,例如设置成f表示允许所有核心参与处理。硬中断本身仍然集中,但后续的协议栈处理被分散开了。

中断亲和性IRQ绑定smp_affinity修改时间:2026-09-28 19:06:46

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0928/63099.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。