中断处理程序不能直接用taskset绑定,需通过修改/proc/irq/*/smp_affinity设置IRQ亲和性,并停用irqbalance、配合ethtool调整RSS队列、锁定ksoftirqd线程及使用udev规则持久化配置。

中断处理程序不能直接用 taskset 绑定
这是最常见的误解:taskset 只能绑定用户态进程或内核线程(如 ksoftirqd/N),而硬件中断(IRQ)本身没有“进程上下文”,无法被 taskset 作用。你看到的“绑定中断”实际是通过修改 IRQ 的亲和性掩码(smp_affinity),让该中断的软中断处理(softirq)尽可能在指定 CPU 上由对应 ksoftirqd/N 线程执行。
查看和修改 IRQ 的 CPU 亲和性:操作 /proc/irq/*/smp_affinity
每个已注册的中断在 /proc/irq/ 下有独立子目录,其 smp_affinity 文件控制可分发到哪些 CPU:
- 查看某 IRQ(比如网卡中断
42)当前亲和性:cat /proc/irq/42/smp_affinity
输出类似ffffffff表示所有 CPU 都可用 - 设为仅 CPU 0(十六进制掩码):
echo 1 > /proc/irq/42/smp_affinity
- 设为 CPU 1 和 CPU 3(对应掩码
0xa,即二进制1010):echo a > /proc/irq/42/smp_affinity
- 注意:写入值必须是合法十六进制,且位数需匹配系统 CPU 数(32 位系统最多 8 字节,64 位系统最多 16 字节);写错会报
Invalid argument
为什么改了 smp_affinity 还没效果?关键依赖点
即使设置了亲和性,中断仍可能出现在其他 CPU,常见原因有:
-
irqbalance服务正在运行 —— 它会定期覆盖/proc/irq/*/smp_affinity,必须先停用:sudo systemctl stop irqbalance
或禁用:sudo systemctl disable irqbalance
- 某些驱动(尤其是现代网卡如 ixgbe、i40e)支持多队列(RSS),但默认 IRQ 可能只绑在第一个队列;需配合
ethtool -X调整接收队列分布,再确认对应 IRQ 编号 - 中断触发后,硬中断处理很快返回,后续 softirq 由
ksoftirqd/N执行 —— 此时若该 CPU 负载高,调度器仍可能迁移到其他 CPU;要真正稳定,还需用taskset锁定ksoftirqd/1等线程:taskset -cp 1 $(pgrep ksoftirqd/1)
持久化设置:重启后不丢失的正确做法
/proc 下的修改重启即失效。可靠方式是:
- 写入
/etc/default/grub的GRUB_CMDLINE_LINUX添加内核参数,例如:isolcpus=1,2 nohz_full=1,2 rcu_nocbs=1,2(用于隔离 CPU 并减少干扰) - 为特定设备 IRQ 设置启动时亲和性,推荐使用
udev规则:
新建/etc/udev/rules.d/90-irq-affinity.rules:SUBSYSTEM=="pci", ATTR{device}=="0x10fb", RUN+="/bin/sh -c 'echo 2 > /proc/irq/$(cat /sys/bus/pci/devices/%p/irq)/smp_affinity'"(需根据实际设备 ID 和 IRQ 动态匹配) - 避免在
/etc/rc.local中 echo —— 此时 PCI 设备 IRQ 可能尚未注册完成,写入会失败
中断亲和性不是开关式配置,它受硬件队列、驱动模型、调度策略和内核版本共同影响;最易忽略的是 irqbalance 的静默覆盖和 softirq 实际执行线程未锁定这两层。











