Linux-2.6.21的负载均衡

2200阅读 1评论2013-10-29 embeddedlwp
分类:LINUX

1负载均衡思想

负载均衡是指多CPU系统(SMP-Symmetric Multi-ProcessorNUMA-Non Uniform Memory Architecture) 中的所有逻辑CPU发挥的功效相当,最大限度地利用所有的硬件资源,从而提高系统的性能。

本文介绍Linux2.6.21内核负载均衡的设计思想。

1.1调度域和调度组

为了充分发挥硬件性能,在多CPU系统上做负载均衡时需要考虑系统的硬件拓朴,调度域正是内核反映CPU硬件结构的一种抽象描述,根据不同的硬件结构自上而下有NUMA、物理、核和超线程四种类型调度域。

系统中的每一个逻辑CPU都会关联一组调度域,相同类型的逻辑CPU处于同一个调度域中。例如,同一个物理CPU的所有核(包括其超线程)处于核域,同一个核的所有超线程处于超线程域。

调度域中又包含有一组调度组,这些调度组反映了此调度域中CPU的拓朴信息,调度组记录的拓朴结构有点类似下一层调度域。例如,核域的每个调度组记录有每个核的超线程信息。另外,调度组中还记录有组内CPU的处理能力,可以区分对待比如超线程CPU等特殊硬件的处理能力。

内核针对不同类型调度域的硬件特性差异配置有不同的负载均衡算法参数称为调度域参数,应用可查看或根据需要调整各CPU的域参数,详见4.1节。

举例:某X86_64服务器,存在有NUMA、核和超线程3个域(注:物理域会被内核优化掉),也就是说每个CPU都关联有三个调度域,见图1

1 CPU0的域结构

1.2任务权重和静态权重

     系统中存在的负载有:中断、异常、软中断、系统调用、任务;系统调用是在任务的上下文中执行的,异常不可控制且一般也是由于任务触发可以忽略,只剩下中断、软中断和任务;有些中断可以通过CPU的中断亲和掩码在多个CPU上做均衡(X86架构中已有此实现,CONFIG_IRQBALANCE),软中断过高的系统可以考虑软中断线程化后算成任务或RPS补丁(CONFIG_NETDEVICES_RPS)将软中断负载均衡至多个CPU间;标准内核的负载均衡算法是针对任务的。

内核为每一个调度实体(本文中即任务)关联一个任务权重load_task,其值是根据优先级计算出来的。在设计时,优先级120的非实时任务权重定为1024,而优先级每差1两者相差10%CPU负载,例如优先级为121的任务权重为820,因为1024/(1024+820)约为55%820/(1024+820)约为45%,这样两者相差为10%;这样就形成了一个任务权重表(实时任务的权值固定为88761*2=177522) 

1 全局权重表

根据上述可以得出优先级与权重的关系见图2

2 任务权重与优先级的关系

算法第一步:计算静态权重

内核在每一个运行队列结构中为当前cpu维护一个静态权重load_rq,其值为此运行队列中的每一个任务权重load_task的总和,load_rq = ∑(load_task)

1.3历史权重

内核为每个运行队列维护了一个cpu_load[5]数组记录一些历史权重信息,此数组在时钟中断的scheduler_tick()中进行更新(初始值为0),算法如下:

M=load_rq, m=cpu_load[i],每次的计算遵循公式:(M-m)/2^i + m,即

i=0:  M-m + m

i=1: (M-m)/2 + m

i=2: (M-m)/4 + m

i=3: (M-m)/8 + m

i=4: (M-m)/16 + m

 

历史权重目的是用来平滑静态权重,以缓解负载均衡时系统性能发生抖动。

1.4动态权重

系统运行过程中,内核会不停地进入负载均衡流程对当前cpu遍历其所关联的所有调度域(自下向上);对每一个调度域遍历所属的所有调度组,找出一个负载最大的调度组(不能是当前cpu所属的调度组);遍历此调度组中所属的cpu,找出静态权重符合条件的目标cpu,最后将此cpu上的可运行任务迁移至当前cpu(称为拉任务),以期达到负载均衡状态。整个过程可抽象为如下步骤:

算法第二步:计算动态权重

负载均衡算法会将静态权重load_rq、调度域参数、历史权重cpu_load[i]等信息,按照一定的规则计算出一个动态权重load,计算规则大致如下:

根据不同的均衡时机(见1.6)和调度域类型(1.1)选择i,根据不同的均衡时机在cpu_load[i]load_rq二者中选取出load_rq值或最小值或最大值作为当前动态权重。

例如,针对物理域和核域进行定时均衡操作时:i2,动态权重取cpu_load[2]load_rq二者中的最大值。

1.5均衡判别

算法第三步:均衡判别规则

有了动态权重后,就可以用来判别系统负载是否均衡了:记当前cpu动态权重值为load_current,目标cpu动态权重值为load_target,判别规则类似如下:

imbalance_pct *load_current < 100*load_target

其中,imbalance_pct为当前cpu的某个调度域参数,例如物理和核域为125

判别结果为真表示目标cpu负载过重,就会从目标cpu迁移任务至当前cpu

1.6负载均衡时机

算法均衡的时机共有定时均衡、闲时均衡、唤醒均衡和创建时均衡四种。

时钟中断时,会根据条件触发均衡软中断(内核为其设置了专门的软中断),

相应均衡函数为load_balance(),此函数只在调度组中的第一个cpu或第一个idle状态cpu上作均衡;此称为定时均衡(又可分为定时忙均衡和定时闲均衡)。

    任务调度时,会检查当前cpu是否空闲,如果空闲则进行负载均衡,相应均衡函数为idle_balance(),与定时均衡相比,只要拉到任务就会返回属于轻量级均衡算法(但实时系统中,此为主要均衡时机,因为发生频率较高);此称为闲时均衡(又称NEW_IDLE均衡)。

    唤醒任务时,会在try_to_wake_up()中根据当前cpu的调度域参数决定是否进行负载均衡;此称为唤醒均衡(唤醒均衡倾向于将被唤醒任务迁移至当前cpu所在的调度域中的某个cpu上,如果系统中存在过于频繁的唤醒,此操作在某些NUMA系统中反而会造成负载不均衡)。

    创建任务时,会在sched_fork()/sched_exec()中,将此任务迁移至一个相对空闲的CPU上运行。称此为创建时均衡(包括forkexecve)

1.7任务迁移

满足1.5节负载均衡判别条件后,内核就会从目标cpu的运行队列中选择任务迁移至当前cpu;任务迁移包括拉任务(一次操作多个任务)和推任务(一次操作一个任务)

拉任务指的是从目的CPU迁移任务至当前CPU,对应实现为pull_task()时均衡、闲时均衡和唤醒均衡对应的是拉任务。

推任务指的是从当前CPU迁移任务至目的CPU,内核在每个运行队列中存放一个内核线程负责处理推任务请求;时均衡多次失败时,置推任务标志,唤醒相应内核线程;创建时均衡(sched_exec),发推任务请求,唤醒相应内核线程;设置任务的cpu亲和掩码时,发推任务请求,唤醒相应内核线程。

实际负载均衡过程中,主要为拉任务操作。

1.8任务迁移规则

算法第四步:任务迁移规则

任务迁移也要符合一定的规则,不同优先级按照由高到低、同种优先级按照LIFO的顺序进行选择任务。但对如下几种类型的任务不能被迁移:

1)        任务的cpu亲和(见1.9)不允许被迁移到当前cpu

2)        为目标cpu上的当前运行任务;

3)   任务具有cache亲和性(参考try_to_wake_up)

4)   任务被迁移到当前cpu上会产生新的失衡。但如果任务迁移到当前cpu后优先级为最高,这时就考虑让优先级高的任务先运行;但如果要迁移的是目标cpu上的最高优先级任务,且最高优先级任务只有一个,也不允许迁移。

1.9任务的cpu亲和

    每一个任务都会关联一个cpu亲和属性,该属性值的每一位表示此任务运行及迁移所允许的cpu集合(置位表示允许),cpu亲和影响均衡操作中的任务迁移(见1.8)。

cpu亲和的设置可通过线程绑定和排它绑定来实现(见2.22.3)。

1.10举例讲解

    由上可知,与均衡算法相关的因素主要有:任务(均指处于运行状态的任务)优先级,任务个数,调度域参数,任务的cpu亲和。

    另外,Linux负载均衡算法没有考虑中断、软中断以及CPU利用率等因素,也不能很好地满足对时延有要求的场景。

 

实例:

a. 双核系统中存在两个逻辑cpu,共四个FIFO任务t1, t2, t3t4

b. t1t2cpu0上运行,t3t4cpu1上运行;

c. 优先级高低关系:t1=t2t3=t4t1为死循环,t2等待中断唤醒执行完业务后睡眠,t3,t4互相唤醒且始终保持交替运行(两个cpu不会idle);

d. 任务都刚创建好准备运行,此时t1t3分别为当前运行任务;

e. 任务均没有设置cpu亲和,即默认允许在所有cpu上运行或迁移。

分析:

此系统存在两个调度域:物理域和核域;由于cpu0cpu1都不会idle,只

会发生定时均衡(无cpu间的唤醒均衡);对于物理域上的定时均衡,因为

只会在调度组中的第一个cpu或第一个idle状态cpu上作均衡,即cpu0

作均衡(见1.6)。

1) 第一步:计算静态权重

load_rq0=177522*2(2个任务)load_rq1=177522*1(1个任务)

2) 第二步:计算动态权重

在物理或核域上进行定时均衡时,用的cpu_load[2],且取cpu_load[2]

load_rq的最大值(见1.4),此时系统刚启动创建好任务,cpu_load[2]

(M-m)/4+m=(M+3m)/4<(M+3M)/4=M,即其值始终小于M,因此,

对于cpu0load_current=load_rq0load_target=load_rq1

对于cpu1load_current=load_rq1load_target=load_rq0

3) 第三步:均衡判别规则

计算公式[100 + (imbalance_pct - 100) / 2]*load_current < 100*load_target,调

度域只有物理和核两个域,imbalance_pct都为125,可简化为:

112*load_current < 100*load_target时,表示需要做负载均衡进行任务迁移:

对于cpu0, 177522*2*112 < 177522*1*100不成立,不需要进行任务迁移。

对于cpu1, 177522*1*112 < 177522*2*100成立,需要进行任务迁移。

4) 第四步:任务迁移规则

对于cpu1的任务迁移,t1不满足迁移条件2,对于t2

a.如果t2优先级低于t3,如果t2迁移到cpu1会造成新的失衡即不符合1.8

节中的迁移条件4t2不允许迁移,均衡失败。

b.如果t2优先级高于t3,而任务迁移到当前cpu后优先级为最高,符合1.8

节中的迁移条件4t2允许迁移,均衡成功。

结论:

如果t2优先级低于t3t2将长期得不到调度,此种情况下要想t2得到及时

运行应用必须合理布置这些线程的cpu亲和。

 

2调优手段

       可以从绑定和调度域两方面入手,对调度均衡相关问题进行调优。

2.1调整域参数

不同类型的调度域参数的详细介绍请参考4.1(阅读此节前请先了解)

对于NUMA硬件架构,如果配置有NUMA功能,内核会为每个CPU初始化一个顶层NUMA域,此域许多参数与其它域不同,例如存在着唤醒拉操作,无NEW_IDLE均衡等等。

内核try_to_wake_up()中会检查本cpu所在的调度域的SD_WAKE_BALANCE标记进入唤醒均衡流程;实时系统中通常会存在太多的唤醒均衡,往往会导致负载不均,可以去掉此标志来禁用NUMA域的唤醒均衡(见1.6)。

 

附内核中默认的NUMA调度域(X86_64)参数值:

#define SD_NODE_INIT (struct sched_domain) {      \

       .span                     = CPU_MASK_NONE,     \

       .parent                  = NULL,                       \

       .child                    = NULL,                    \

       .groups                  = NULL,                    \

       .min_interval         = 8,                           \

       .max_interval         = 32,                          \

       .busy_factor           = 32,                          \

       .imbalance_pct       = 125,                        \

       .cache_nice_tries    = 2,                           \

       .busy_idx                  = 3,                           \

       .idle_idx             = 2,                           \

       .newidle_idx          = 0,                           \

       .wake_idx              = 1,                           \

       .forkexec_idx         = 1,                           \

       .flags                    = SD_LOAD_BALANCE     \

                                  | SD_BALANCE_FORK   \

                                  | SD_BALANCE_EXEC   \

                                  | SD_SERIALIZE             \

                                  | SD_WAKE_BALANCE,  \

       .last_balance          = jiffies,                     \

       .balance_interval    = 1,                           \

       .nr_balance_failed  = 0,                           \

}

2.2线程绑定

线程绑定是针对任务的,可将某个任务绑定到一个cpu集合。

对于特殊业务关联性比较强的任务,不允许在同一个cpu上运行,由于内核看不到此关联性不能保证这些任务不调度到同一个cpu上,就需要对这些任务执行线程绑定,这样内核在做负载均衡时就不会将这些任务迁移至不允许的cpu上面运行了(见1.8节的任务迁移条件1)。

 

3调度域参数

负载均衡不单单是均衡任务,还要考虑在均衡任务的同时兼顾硬件资源的最高效的利用,因此负载均衡算法与硬件的架构密切相关,不同的硬件架构在算法中抽象出不同的调度域。硬件架构主要有:UP架构,SMP 架构和NUMA 架构,这些架构从硬件层次可分为:NUMA节点、物理、核和超线程四个层次,分别对应内核负载均衡算法中的四种调度域类型。

3.1调度域参数

通过“/proc/sys/kernel/sched_domain/cpu/domain/”查看或根据需要修改不同CPU对应的域参数值,此功能的开启需要在配置内核时选用宏CONFIG_SMPCONFIG_SCHED_DEBUGCONFIG_SYSCTL

实际应用中,需要针对单板的硬件架构选用合适的内核宏进行调度域的初始化。例如,针对多核以及超线程的架构,需要配置宏CONFIG_SMPCONFIG_SCHED_MCCONFIG_SCHED_SMT来通知内核来为此单板建立核域和超线程域。

内核的调度域结构:

1) 结构中前三个字段的作用是将内核启动后初始化好的所有的调度域和调度组联系起来,span字段表示调度域包含的CPU集合,这四个字段的含义参考下1.1节中的图1就明白了。

这里再强调下对于系统中的每一个CPU都有一个图1这样的结构,每个CPU的调度域结构是独立分配的,修改其中一个不会影响到另一个;而不同CPU的调度域中的调度组结构可能是共享的,例如图1CPU0的调度组和CPU8的调度组实际上是共享的(CPU0CPU8一对超线程),调度组在内核初始化后就固定了,不允许修改。

2) last_balance记录了上次做时均衡的时间点,单位为tick,只在时均衡中更新,和balance_interval一起用于计算下次做时均衡的时间;

3) balance_interval也只在时均衡中更新,单位为毫秒,用于计算下次做时均衡的时间:last_balance+msecs_to_jiffies(balance_interval),最终根据情况将结果更新记录于运行队列rq->next_balance中;时均衡成功迁移任务后,意味着此时系统的负载倾向于不均衡,将balance_interval置为min_interval时均衡没有发生任务迁移,意味着此时系统的负载倾向于均衡,将balance_interval加倍,但不超过max_interval(如果当前CPU的任务都已绑定,则不超过MAX_PINNED_INTERVAL,定义为512ms)

4) busy_factor只用于定时均衡,如果当前CPU不是空闲的(定时忙平衡),就将变量interval间隔乘上此字段,这样在当前CPU忙时不会太频繁进入负载均衡算法,避免负载均衡算法本身带来较大的开销。

5) imbalance_pct用作均衡判别,见1.5节;此值增大可放宽负载失衡的判别条件,从而降低负载均衡的频率;

6) cache_nice_triesnr_balance_failed用于定时均衡中连续迁移任务失败后,发起推任务操作,判断条件为nr_balance_failed > (cache_nice_tries+2)

7) busy_idx, idle_idx, newidle_idx, wake_idx, forkexec_idx用作下标选择运行队列中的历史权重cpu_load[]数组中的元素,见1.4节;

8) flags用于配置不同的均衡算法以及一些特殊的标志,其值含义如下:

a) SD_LOAD_BALANCE表示做负载均衡;做负载均衡就会做定时均衡,定

时均衡不能单独关闭;

b) SD_BALANCE_NEWIDLE表示做闲时均衡;

c) SD_BALANCE_EXEC表示做创建时均衡中的execve均衡;

d) SD_BLANCE_FORK表示做创建时均衡中的fork均衡;

e) SD_WAKE_IDLE表示开启超线程后在try_to_wake_up()中将被唤醒任务

迁移至一个空闲CPU的上运行(如果有的话)

f) SD_WAKE_AFFINE表示在try_to_wake_up()中考虑任务的cache亲和,如

果存在cache亲和就不将此任务拉至当前CPU

g) SD_WAKE_BALANCE功能类似于SD_WAKE_AFFINE,只是算法判别

准则不同;

h) SD_SHARE_CPUPOWER表示共享CPU的处理能力,主要用于同一个核的超线程CPU间;从而让操作系统感知到超线程硬件特性予以特殊处理;

i) SD_SHARE_PKG_RESOURCES用于初始化调度组的CPU能力;

j) SD_SERIALIZE主要用于不同CPU间的负载均衡算法的串行化(增加了一把自旋锁),一般NUMA域可设置此选项;

k) BALANCE_FOR_MC_POWERBALANCE_FOR_PKG_POWER用于节能,负载均衡可以和CPU的变频技术以及S5节能技术结合起来,用以将空闲的CPU降频或休眠,具体可参考find_busiest_group()函数的实现,基本思想就是开启节能选项后(选项开关可通过sched_mc_power_savingssched_smt_power_savings控制选中SD_POWERSAVINGS_BALANCE)将负载轻的CPU的任务迁移至负载重的CPU,直至系统中产生空闲的CPU

3.2唤醒均衡

唤醒均衡涉及的拉操作包括SD_WAKE_AFFINESD_WAKE_BALANCE两种,主要是为了实现任务的cache亲和算法,以减少CPU间的迁移带来的cachetlb等硬件资源的开销,以提高系统的性能。

3.2.1算法思想

任务的亲和性计算是指在被唤醒时选择一个可运行的CPU,该CPU最好保存有任务以前的cache内容。任务的亲和性计算在try_to_wake_up中进行,计算内容是在任务所属CPU和执行唤醒操作的本地CPU之间选择一个运行,选择的依据是CPUcache内容是否失效和CPU的负载情况。

Linux 2.6最初的亲和性计算是为每个调度域设一个cache失效的时间值,当被唤醒任务的睡眠时间超过失效时间时就认为任务与CPU之间已失去亲和性。这种算法的缺点是无法准确估计cache是否失效,因为如果一个时间片很长的任务一直在运行那么cache失效的可能性就很小。当前Linux 2.6的亲和性计算是根据CPU的任务切换频率来估计cache的失效可能性,如果有很多时间片很短的任务在CPU上运行,那么cache失效的可能性就很大。

下面详细描述当前内核对任务亲和性的计算过程,以下使用本地CPU代表执行唤醒操作的CPU,而目的CPU代表任务所属的CPU

1)        首先取得目的CPU的权重值load和本地CPU的权重值this_load,由运行队列的cpu_loadraw_weighted_load确定一个平滑值。其中目的CPU取平滑低值,本地CPU取平滑高值。

2)        计算本地CPU的任务平均权重值。

3)        如果是同步唤醒(即进行唤醒操作以后不立即进行调度,当前任务继续运行),为了减小当前唤醒操作对权重值的影响,因此需要从本地CPU的权重值中减去当前任务的权重;否则直接取本地CPU权重值this_load

4)        以如下条件判断目的CPU与任务之间不具亲和性,如果条件成立则选择本地CPU;否则认为目的CPU与任务之间具有亲和性,进行步骤5)的判断。

(tl<=load && tl+target_load(cpu,idx)<=tl_per_task)  ||

100*(tl+p->load_weight)<=imbalance*load

其中tl是根据步骤3)取得的本地CPU的权重值;load是目的CPU的权重值;target_load计算目的CPU权重的峰值;tl_per_task是本地CPU的任务平均权重值;p->load_weight是被唤醒任务的权重值;imbalance是负载平衡系数。

假设cond1=(tl<=load && tl+target_load(cpu,idx)<=tl_per_task)

     cond2=100*(tl+p->load_weight)<=imbalance*load

上式可以简化为表达式1 (cond1 || cond2)

那么具有亲和性(任务仍选择目的CPU)的条件可以改写为表达式2 (!cond1 && !cond2)

如果条件cond1cond2其中一个为真则认为目的CPU与任务之间不具亲和性。下面对这两个条件进行进一步分析:

Ø  cond1中可以看出,只有在同步唤醒条件下,tl才会小于tl_per_task;从cond1中可以分析出只有在target_load(cpu,idx)很小的情况下才会为真。因为目的CPU在权重值很小的情况下任务会发生频繁的切换,这时cache内容失效的可能性很大。 因此cond1为真时认为目的CPU已不具有亲和性

Ø  表达式2为真则表示被唤醒任务应该在目的CPU运行。在假设!cond1成立的情况下,表达式2!cond2成立的条件可以转换为:100*(tl+p->load_weight) > imbalance*load

等价于(tl+p->load_weight) > (imbalance/100)*load

imbalance/100值恒大于1,在以load为参考值的情况下,!cond2为真则可以认为(tl+p->load_weight)的值较大,也即本地CPU加上被唤醒任务以后负载会加重,而相对而言目的CPU的负载较轻,在考虑cache内容有效的条件下就倾向于将被唤醒任务放在目的CPU运行。反之cond2为真则认为任务不适合在目的CPU上运行。

5)        经过步骤4)的判断以后,如果目的CPU和任务之间具有亲和性,即cond1cond2条件同时为假,那么应该选择目的CPU。这时目的CPUcache失效的可能性小且任务加在本地CPU上以后会造成负载失衡。对于任务加在本地CPU上造成负载失衡的原因,可以分为三种情况:

                                                    i.              本地CPU负载小于目的CPU,且处于失衡状态。但任务权重很大,在本地CPU加上任务以后打破了失衡,使本地CPU负载反大于目的CPU而产生新的失衡;但如果将任务加载目的CPU上反而会扩大失衡。

                                                  ii.              本地CPU负载接近目的CPU,处于均衡状态。本地CPU权重加上任务权重以后造成负载的失衡。

                                                iii.              本地CPU负载大于目的CPU,且处于失衡状态。这时本地CPU加上任务以后使失衡更加扩大。

对于情况a)鼓励将任务加在本地CPU上;对于情况b)在考虑cache有效性的因素下鼓励任务加在目的CPU上;对于情况c)鼓励任务加在目的CPU上。

因此在调度域设置允许的情况下需要对本地CPU和目的CPU的负载进行判断,判断的条件如下:

imbalance*this_load <= 100*load

等价于(imbalance/100)*this_load <= load

其中this_load是本地CPU的权重值;imbalance是负载平衡系数;load是目的CPU的权重值。

(imbalance/100)恒大于1,因此可以看出,如果条件成立那么目的CPU与本地CPU的权重值之比超过负载平衡系数,而产生负载失衡。

如果以上的条件成立则出现了情况a),这时应选择本地CPU;否则应选择目的CPU

3.2.2算法缺陷

然而实时性系统多为实时任务,实时任务的权重值固定为177522(见1.2节),再加上某些业务过高的网络软中断的影响,导致内核原有的亲和算法不能很好地发挥作用,反而会起到副作用。

1. 在电信级业务的场景中,NUMA域默认参数存在两个问题。

a)产品会伴随着大量的网络收发包,进而产生大量的网口中断和软中断,频繁的网络软中断就会产生大量的唤醒任务操作,导致唤醒均衡算法不停地将任务拉至中断所在的NUMA节点的CPU上;

b)同时很多业务对系统中每一个CPU的利用率比较敏感,要求各个CPU利用率严格均衡。

所以需要更改NUMA域的默认配置参数来解决这两个问题:

1个需要去掉NUMA域的唤醒均衡;第2个需要配上NUMA域的闲时均衡。

2. 超线程域默认参数配有SD_WAKE_AFFINE算法。

此参数在某些业务场景会导致系统性能发生抖动,进而影响系统性能;但与SD_WAKE_BALANCE算法相比影响相对较小,在出现开启硬件超线程特性后如果出现了性能抖动,就可以考虑去除此参数。

3.3七种硬件模型

本节介绍常见的多CPU硬件架构的调度域推荐配置情况。

3.3.1 内核选项的推荐配置

Linux内核只处理了x86平台,其它架构如mips/arm/ppc等无对应配置;例如某mips64 xlr系列单板上开启了超线程后有32CPU,只有1个物理域,包含有32个调度组,这样会增加负载均衡算法遍历的时间。

内核选项的配置请务必与实际的硬件架构配置,这样才能达到最好的性能和均衡效果;例如,对非NUMA架构的硬件单板配上了CONFIG_NUMA就有可能存在NUMA调度域。

1.       单物理CPU,一个核,有超线程

CONFIG_SMP, CONFIG_SCHED_SMT

2.       单物理CPU,多个核,无超线程

CONFIG_SMP, CONFIG_SCHED_MC

3.       单物理CPU,多个核,有超线程

CONFIG_SMP, CONFIG_SCHED_MC, CONFIG_SCHED_SMT

4.       单节点,多物理CPU,每个物理CPU有多个核,无超线程

CONFIG_SMP, CONFIG_SCHED_MC

5.       单节点,多物理CPU,每个物理CPU有多个核,有超线程

CONFIG_SMP, CONFIG_SCHED_MC, CONFIG_SCHED_SMT

6.       多节点,多物理CPU,每个物理CPU有多个核,无超线程

CONFIG_SMP, CONFIG_NUMA, CONFIG_SCHED_MC

7.       多节点,多物理CPU,每个物理CPU有多个核,有超线程

CONFIG_SMP, CONFIG_NUMA, CONFIG_SCHED_MC, CONFIG_SCHED_SMT

3.3.3调度域层次的优化

内核初始化时根据所配置的宏激活不同的调度域初始化分支,依次生成3.3.1小节中所配内核宏对应的调度域类型,最终还会根据一定的规则去删除一些不必要的调度域,最终得到一个优化过的调度域层次。例如1.1小节的图1中的物理域最终会被优化掉。

大致优化规则:

1) 调度域中只包含1CPU,则将此调度域优化掉;

2) 调度域中只有一个调度组,且无SD_WAKE_IDLE, SD_WAKE_AFFINESD_WAKE_BALANCE标志,则将此调度域优化掉;

3) 两个相邻的父子调度域中所包含的CPU集合相同,并且flags值也相同,则将父调度域优化掉。

 

详细实现细节请参考cpu_attach_domain()内核代码。

3.4影响系统性能和抖动的几个重要参数

会严重影响系统负载均衡效果,以及可能会对系统造成较大性能或性能抖动问题几个调度域参数总结如下:

1. flags选择不同的负载均衡算法,其值的不同会直接影响系统的负载均衡效果以及性能;其中最重要的是唤醒均衡和闲时均衡算法。

2. newilde_idx, busy_idx, idle_idx选择不同的历史负载,这些参数设置的不合理会直接导致系统出现性能抖动;通常值越小越倾向于抖动;
        3. imbalance_pct
会影响均衡判别的结果(见1.5节),如果发现负载均衡影响了性能,可尝试将此值调大,偏顶层的调度域建议将其调得越高;注意此值应恒大于零。

另外,不同层次的调度域,请注意各自参数的不同配置。

 

3.5其它
1) /proc/schedstat记录了负载均衡的详细数据(需要配置CONFIG_SCHEDSTATS),其
   中各个字段的的详细含义可以参考Documentation/sched-stats.txt
2) 通过初始化时设置cpu_isolated_map可以将某些CPU隔离出负载均衡。
 
 
4参考资料

1.  Professional Linux Kernel Architecture

2.  

上一篇:B树的删除操作
下一篇:My contribution to linux kernel and qemu

文章评论