Linux中断负载均衡

     Linux 内核需要对连接到计算机上的所有硬件设备进行管理,毫无疑问这是它的份内事。如果要管理这些设备,首先得和它们互相通信才行,一般有两种方案可实现这种功能:

  1. 轮询(polling 让内核定期对设备的状态进行查询,然后做出相应的处理;
  2. 中断(interrupt 让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。

    第一种方案会让内核做不少的无用功,因为轮询总会周期性的重复执行,大量地耗用 CPU 时间,因此效率及其低下,所以一般都是采用第二种方案 。

 

    对于中断,Linux也有自己的负载均衡策略,既可以调用Linux自己的优化模块irqbalance来实现自动的优化调节,也可以人为的将中断进行绑定的固定的物理CPU上。

 

1、irqbalance

(1)irqbalance简介与使用

        irqbalance用于优化中断分配,它会自动收集系统数据以分析使用模式,并依据系统负载状况将工作状态置于 Performance mode 或 Power-save mode。处于Performance mode 时,irqbalance 会将中断尽可能均匀地分发给各个 CPU core,以充分利用 CPU 多核,提升性能。处于Power-save mode 时,irqbalance 会将中断集中分配给第一个 CPU,以保证其它空闲 CPU 的睡眠时间,降低能耗。

         irqbalance这个进程默认是开机启用的,可以通过如下命令它的状态

# service irqbalance status
irqbalance (pid PID) is running…

        对于人为将中断绑定到CPU上的情况时,为了消除irqbalance的自适应调节,需要将该进程关闭,可以用下面的命令关闭它:

# service irqbalance stop
Stopping irqbalance: [ OK ]

或者干脆取消开机启动:

# chkconfig irqbalance off

(2)irqbalance原理分析

      irqbalance的意义在于SMP系统的中断优化,而SMP架构是一种CPU的分层拓扑,如下图所示

       一个NUMA node包括一个或者多个Socket,以及与之相连的local memory。一个多核的Socket有多个Core。如果CPU支持超线程并开启,操作系统还会把这个Core看成 2个Logical Processor。因此irqbalance会需要考虑到各个CPU上的中断负载以及CPU所处的拓扑位置来进行中断优化调节。

     irqbalance的源码下载可以到github网站https://github.com/Irqbalance

     个人对其源码的分析在https://github.com/lkn910907/Code-analyze/tree/master/irqbalance%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90,可便于新手了解。

//irqbalance.c
int main(int argc, char** argv)
{
  /* ... */
  while (keep_going) {
                sleep_approx(SLEEP_INTERVAL); //#define SLEEP_INTERVAL 10
                /* ... */
                clear_work_stats();
                parse_proc_interrupts();
                parse_proc_stat();
                /* ... */
                calculate_placement();
                activate_mappings();
                /* ... */
}
/* ... */
}

     从程序的主循环可以很清楚的看到它的逻辑,在退出之前每隔10秒它做了以下的几个事情:
1. 清除统计
2. 分析中断的情况
3. 分析中断的负载情况
4. 根据负载情况计算如何平衡中断
5. 实施中断亲和性变更

     如果不了解中断亲和性可以下面找到详细说明 ~

     在诊断模型下运行irqbalance可以给我们很多详细的信息:

#irqbalance  –debug

     可以详细看到irqbalcne对每个CPU的拓扑分层,以及每个拓扑域上的负载。

 

(2)自己设置中断亲和性

     在 SMP 体系结构中,我们可以通过调用系统调用和一组相关的宏来设置 CPU 亲和力(CPU affinity),将一个或多个进程绑定到一个或多个处理器上运行。中断在这方面也毫不示弱,也具有相同的特性。中断亲和力是指将一个或多个中断源绑定到特定的 CPU 上运行。中断亲和力最初由 Ingo Molnar 设计并实现。

     在 /proc/irq 目录中,对于已经注册中断处理程序的硬件设备,都会在该目录下存在一个以该中断号命名的目录 IRQ#IRQ# 目录下有一个 smp_affinity 文件(SMP 体系结构才有该文件),它是一个 CPU 的位掩码,可以用来设置该中断的亲和力, 默认值为 0xffffffff,表明把中断发送到所有的 CPU 上去处理。如果中断控制器不支持 IRQ affinity,不能改变此默认值,同时也不能关闭所有的 CPU 位掩码,即不能设置成 0x0

     需要注意的是人为设置中断亲和性需要关闭irqbalance,消除其自适应中断调节

        

     我们以网卡(eth1,中断号 44 )为例,在具有 8 个 CPU 的服务器上来设置网卡中断的亲和力(以下数据出自内核源码Documentation\IRQ-affinity.txt):

[root@moon 44]# cat smp_affinity
ffffffff
[root@moon 44]# echo 0f > smp_affinity
[root@moon 44]# cat smp_affinity
0000000f

     当我们通过 echo 命令将 CPU 掩码写进 smp_affinity 文件时,此时的调用路线图为:write() ->sys_write() ->vfs_write() ->proc_file_write() ->irq_affinity_write_proc() ->set_affinity() ->set_ioapic_affinity() ->set_ioapic_affinity_irq() ->io_apic_write();其中在调用 set_ioapic_affinity_irq() 函数时,以中断号和 CPU 掩码作为参数,接着继续调用 io_apic_write(),修改相应的中断重定向中的值,来完成中断亲和力的设置。

     对于效果的检验,可以通过cat /proc/interrupts命令查看中断在各个CPU上的分布,如果是对特定中断处理,再加上grep过滤更方便查看。通过可以发现,一旦设置了亲和性,中断就只在特定的CPU上触发了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章