Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity)

硬件中断发生频繁,是件很消耗 CPU 资源的事情,在多核 CPU 条件下如果有办法把大量硬件中断分配给不同的 CPU (core) 处理显然能很好的平衡性能。现在的服务器上动不动就是多 CPU 多核、多网卡、多硬盘,如果能让网卡中断独占1个 CPU (core)、磁盘 IO 中断独占1个 CPU 的话将会大大减轻单一 CPU 的负担、提高整体处理效率。VPSee 前天收到一位网友的邮件提到了 SMP IRQ Affinity,引发了今天的话题:D,以下操作在 SUN FIre X2100 M2 服务器+ 64位版本 CentOS 5.5 + Linux 2.6.18-194.3.1.el5 上执行。

什么是中断

中文教材上对 “中断” 的定义太生硬了,简单的说就是,每个硬件设备(如:硬盘、网卡等)都需要和 CPU 有某种形式的通信以便 CPU 及时知道发生了什么事情,这样 CPU 可能就会放下手中的事情去处理应急事件,硬件设备主动打扰 CPU 的现象就可称为硬件中断,就像你正在工作的时候受到 QQ 干扰一样,一次 QQ 摇头就可以被称为中断。

中断是一种比较好的 CPU 和硬件沟通的方式,还有一种方式叫做轮询(polling),就是让 CPU 定时对硬件状态进行查询然后做相应处理,就好像你每隔5分钟去检查一下 QQ 看看有没有人找你一样,这种方式是不是很浪费你(CPU)的时间?所以中断是硬件主动的方式,比轮询(CPU 主动)更有效一些。

好了,这里又有了一个问题,每个硬件设备都中断,那么如何区分不同硬件呢?不同设备同时中断如何知道哪个中断是来自硬盘、哪个来自网卡呢?这个很容易,不是每个 QQ 号码都不相同吗?同样的,系统上的每个硬件设备都会被分配一个 IRQ 号,通过这个唯一的 IRQ 号就能区别张三和李四了。

在计算机里,中断是一种电信号,由硬件产生,并直接送到中断控制器(如 8259A)上,然后再由中断控制器向 CPU 发送信号,CPU 检测到该信号后,就中断当前的工作转而去处理中断。然后,处理器会通知操作系统已经产生中断,这样操作系统就会对这个中断进行适当的处理。现在来看一下中断控制器,常见的中断控制器有两种:可编程中断控制器 8259A 和高级可编程中断控制器(APIC),中断控制器应该在大学的硬件接口和计算机体系结构的相关课程中都学过。传统的 8259A 只适合单 CPU 的情况,现在都是多 CPU 多核的 SMP 体系,所以为了充分利用 SMP 体系结构、把中断传递给系统上的每个 CPU 以便更好实现并行和提高性能,Intel 引入了高级可编程中断控制器(APIC)。

光有高级可编程中断控制器的硬件支持还不够,Linux 内核还必须能利用到这些硬件特质,所以只有 kernel 2.4 以后的版本才支持把不同的硬件中断请求(IRQs)分配到特定的 CPU 上,这个绑定技术被称为 SMP IRQ Affinity. 更多介绍请参看 Linux 内核源代码自带的文档:linux-2.6.31.8/Documentation/IRQ-affinity.txt

如何使用

先看看系统上的中断是怎么分配在 CPU 上的,很显然 CPU0 上处理的中断多一些:

# cat /proc/interrupts 
           CPU0       CPU1       
  0:  918926335          0    IO-APIC-edge  timer
  1:          2          0    IO-APIC-edge  i8042
  8:          0          0    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
 12:          4          0    IO-APIC-edge  i8042
 14:    8248017          0    IO-APIC-edge  ide0
 50:        194          0   IO-APIC-level  ohci_hcd:usb2
 58:      31673          0   IO-APIC-level  sata_nv
 90:    1070374          0         PCI-MSI  eth0
233:         10          0   IO-APIC-level  ehci_hcd:usb1
NMI:       5077       2032 
LOC:  918809969  918809894 
ERR:          0
MIS:          0

为了不让 CPU0 很累怎么把部分中断转移到 CPU1 上呢?或者说如何把 eth0 网卡的中断转到 CPU1 上呢?先查看一下 IRQ 90 中断的 smp affinity,看看当前中断是怎么分配在不同 CPU 上的(ffffffff 意味着分配在所有可用 CPU 上):

# cat /proc/irq/90/smp_affinity 
7fffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff

在进一步动手之前我们需要先停掉 IRQ 自动调节的服务进程,这样才能手动绑定 IRQ 到不同 CPU,否则自己手动绑定做的更改将会被自动调节进程给覆盖掉。如果想修改 IRQ 90 的中断处理,绑定到第2个 CPU(CPU1):

# /etc/init.d/irqbalance stop

# echo "2" > /proc/irq/90/smp_affinity

(上面的 echo “2” 是怎么来的?为什么是 ”2“?请参考这篇:计算 SMP IRQ Affinity)过段时间在看 /proc/interrupts,是不是 90:eth0 在 CPU1 上的中断增加了(145)、在 CPU0 上的中断没变?不断打印 /proc/interrupts 就会发现 eth0 在 CPU0 上的中断数始终保持不变,而在 CPU1 上的中断数是持续增加的,这正是我们想要的结果:

# cat /proc/interrupts 
           CPU0       CPU1       
  0:  922506515          0    IO-APIC-edge  timer
  1:          2          0    IO-APIC-edge  i8042
  8:          0          0    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
 12:          4          0    IO-APIC-edge  i8042
 14:    8280147          0    IO-APIC-edge  ide0
 50:        194          0   IO-APIC-level  ohci_hcd:usb2
 58:      31907          0   IO-APIC-level  sata_nv
 90:    1073399        145         PCI-MSI  eth0
233:         10          0   IO-APIC-level  ehci_hcd:usb1
NMI:       5093       2043 
LOC:  922389696  922389621 
ERR:          0
MIS:          0

有什么用

在网络非常 heavy 的情况下,对于文件服务器、高流量 Web 服务器这样的应用来说,把不同的网卡 IRQ 均衡绑定到不同的 CPU 上将会减轻某个 CPU 的负担,提高多个 CPU 整体处理中断的能力;对于数据库服务器这样的应用来说,把磁盘控制器绑到一个 CPU、把网卡绑定到另一个 CPU 将会提高数据库的响应时间、优化性能。合理的根据自己的生产环境和应用的特点来平衡 IRQ 中断有助于提高系统的整体吞吐能力和性能。

VPSee 经常收到网友来信问到如何优化 Linux、优化 VPS、这个问题不太好回答,要记住的是性能优化是一个过程而不是结果,不是看了些文档改了改参数就叫优化了,后面还需要大量的测试、监测以及持续的观察和改进。

评论 (20 Comments)

  1. 把irqbalance 停掉會不會有其他問題出玩?

  2. 不会有什么严重问题,但是没有 irqbalance 也没有合理的做手动 irq 绑定的话会有性能问题。手动 irq 只推荐给很 heavy、很特殊的情况,比如带多网卡多硬盘的网络存储服务器,一般机器一般应用还是用 irqbalance 省心。

    事实上以前 Linux 是不推荐使用 irqbalance 的,原因在于当时的 irqbalance 实现很简单,没有什么优化作用,后来的 irqbalance (cache topology + power aware) 有了很大改进,在多核上表现良好。

  3. 分别将2个网卡中断到2不同的CPU上也防止他们在CPU间切换 是个很不错的方法哦 . 也开始研究中断了. ?哈哈

  4. 将不2个网卡中断到不同的CPU上 是个很不错的想法 省去了系统频繁的切换 怎么也开始研究中断啦?

  5. 呵呵,刚好你上次在邮件里问到了怎么算 smp_affinity,发现是个好题材可以写一篇文:D

  6. 我想问下cat /proc/interrupts显示出来的数据里面倒数第二行的LOC代表什么

  7. LOC 代表 Local timer interrupts

  8. 请问为什么我机器上的irqbalance 服务停掉了,eth0的中断也成功绑定到CPU1,但机器一重启eth0的中断还是在CPU0上处理

  9. 你可能没有保存设置吧?把命令加到启动文件中,这样系统启动后就自动执行绑定。

  10. 请问vpsee有没有试过将一块网卡上的中断绑定到多个CPU上?
    我们试到现在还没有成功过,内核2.6.27,网卡型号Broadcom NetXtreme II BCM5709

  11. 这是个很好的视点。以前基本上没有从这个层面对机器的性能进行监测和调优过。非常好的文章,会尝试着在一些场合测试下调优的性能对比。 非常感谢。

  12. 请教VPSEE,这方法支持2.6.18kernel吗?

  13. @Anonymous

    以下操作在 SUN FIre X2100 M2 服务器+ 64位版本 CentOS 5.5 + Linux 2.6.18-194.3.1.el5 上执行。

  14. [root@ling21 irq]# cat /proc/interrupts | grep eth0
    138: 94 0 0 0 0 0 0 0 0 0 0 0 1658246 0 2326067 25400 PCI-MSI-X eth0
    146: 21 514 190874 0 195805 1363 183713 0 0 960 207714 1069 109395 6648 62368 22054 PCI-MSI-X eth0
    154: 22 117 228975 24561 138760 316 298306 0 0 23 155098 2822 89516 2092 46487 5793 PCI-MSI-X eth0
    162: 27 10262 214082 14 152023 64 109847 0 0 741 192493 5129 246456 5869 111141 1219 PCI-MSI-X eth0
    170: 25 0 164516 4197 200882 191 134353 0 0 142 203712 2573 128920 50 52287 6093 PCI-MSI-X eth0
    178: 24 0 115633 385 142644 0 226270 0 0 0 180040 146 87892 25477 221183 1625 PCI-MSI-X eth0
    186: 21 18545 370788 197 191823 0 125879 0 0 2526 294249 6214 145805 5406 99030 8105 PCI-MSI-X eth0
    [root@ling21 irq]# ls
    0 1 10 11 12 13 138 14 146 15 154 162 170 178 186 2 3 4 5 50 58 6 66 7 74 8 82 9 90 98
    [root@lingcloud21 irq]# cat 138/
    eth0/ smp_affinity
    [root@lingcloud21 irq]# cat 138/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00001000
    [root@lingcloud21 irq]# cat 146/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000010
    [root@lingcloud21 irq]# cat 154/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00004000
    [root@lingcloud21 irq]# cat 162/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000010
    [root@lingcloud21 irq]# cat 170/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000004
    [root@lingcloud21 irq]# cat 178/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00004000
    [root@lingcloud21 irq]# cat 186/smp_affinity
    00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000040

    hi,我的网卡绑定默认就如上,出现7个irq号,而且绑定时好像有两对都绑定到一个CPU上,不知道怎么回事儿,请帮忙解释一下?谢谢!

  15. 不错的文章!我在我的系统中做试验,发现即使irqbalance打开,系统默认的affinity是1的情况下,绝大多数中断是被CPU0处理。当修改为3时,才交替进行。似乎irqbalance没有overwrite smp_affinity。求解。

  16. @Max
    好像在 linux 2.6 中,如果配置了相关内核参数的话 kernel 能自己做 irq balancing,不需要另外的 irqbalance daemon,所以这里讲的 irqbalance 服务进程是多余的。怀疑你的内核 disable 了这个 irq balancing.

  17. 改了还是不生效。ibm x3650 centos 5.6 64bit
    CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
    0: 2850459599 0 0 0 0 0 0 0 IO-APIC-edge timer
    1: 0 0 0 0 0 0 0 0 IO-APIC-edge i8042
    8: 1 0 0 0 0 0 0 0 IO-APIC-edge rtc
    9: 1 0 0 0 0 0 0 0 IO-APIC-level acpi
    14: 25 0 0 0 0 0 0 0 IO-APIC-edge ide0
    74: 52 0 0 0 0 0 0 0 IO-APIC-level ehci_hcd:usb1, uhci_hcd:usb2, uhci_hcd:usb4
    82: 0 0 0 0 0 0 0 0 IO-APIC-level uhci_hcd:usb3
    106: 11665 0 0 616685 0 144816 0 0 PCI-MSI eth0
    114: 1210473344 0 0 0 0 0 0 1004015714 PCI-MSI eth1
    169: 4665 0 35359 0 5903396 8330 0 0 IO-APIC-level aacraid
    NMI: 1051178 313597 192075 193883 174325 156836 173381 224235
    LOC: 2848392731 2848422064 2849181891 2849181961 2849718295 2849717988 2849513570 2849427267
    ERR: 0
    MIS: 0

  18. fedora18测试,用systemctl stop irqbalance.service停掉服务后echo “3”>/proc/irq/XX/smp_affinity,然后再启动服务,发现过几秒后值又变回来了。中断还是集中在CPU0上,而CPU1上还是0。

  19. 如何恢复为默认7fffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff啊?我改了不好

  20. irqbalance 没看到这个
    ps -ef|grep irq
    会出现
    root 4 2 0 Apr28 ? 00:01:54 [ksoftirqd/0]
    root 9 2 0 Apr28 ? 00:00:11 [ksoftirqd/1]
    root 13 2 0 Apr28 ? 00:00:06 [ksoftirqd/2]
    root 17 2 0 Apr28 ? 00:00:10 [ksoftirqd/3]
    root 21 2 0 Apr28 ? 00:00:03 [ksoftirqd/4]
    root 25 2 0 Apr28 ? 00:00:06 [ksoftirqd/5]
    root 29 2 0 Apr28 ? 00:00:17 [ksoftirqd/6]
    root 33 2 0 Apr28 ? 00:00:07 [ksoftirqd/7]

    内核为 linux 2.6.35

发表评论