预览加载中,请您耐心等待几秒...
1/10
2/10
3/10
4/10
5/10
6/10
7/10
8/10
9/10
10/10

亲,该文档总共14页,到这已经超出免费预览范围,如果喜欢就直接下载吧~

如果您无法下载资料,请参考说明:

1、部分资料下载需要金币,请确保您的账户上有足够的金币

2、已购买过的文档,再次下载不重复扣费

3、资料包下载后请先用软件解压,在使用对应软件打开

linux在多核处理器上的负载均衡原理linux在多核处理器上的负载均衡原理:现在互联网公司使用的都是多CPU(多核)的服务器了,Linux操作系统会自动把任务分配到不同的处理器上,并尽可能的保持负载均衡。那Linux内核是怎么做到让各个CPU的压力均匀的呢?做一个负载均衡机制,重点在于:1.何时检查并调整负载情况?2.如何调整负载?先看第一个问题。如果让我这样的庸俗程序员来设计,我第一个想到的就是每隔一段时间检查一次负载是否均衡,不均则调整之,这肯定不是最高效的办法,但肯定是实现上最简单的。实际上,2.6.20版linuxkernel的确使用软中断来定时调整多CPU上的压力(调用函数run_rebalance_domains),每秒1次。但每秒一次还是不能满足要求,对很多应用来说,1秒太长了,一秒钟内如果发生负载失衡对很多web应用都是不能接受的,何况其他实时应用。最好kernel能够紧跟进程的变化来调整。那么,好,我们在进程创建和进程exit的时候检查并调整负载呢?可以,但是不完整,一个进程创建以后如果频繁的睡眠、醒来、睡眠、醒来,它这样折腾对CPU的负载是有影响的,你就不管它了吗?说到底,我们其实关注的是进程是否在使用CPU,而不是它是否诞生了。所以,我们应该在进程睡眠和醒来这两个时间点检查CPU们的负载。再看第二个问题,怎么调整负载呢?从最繁忙的那个CPU上挪一个进程到最闲的那个CPU上,如果负载还不均衡,就再挪一个进程,如果还不均衡,继续挪....这也是个最笨的方法,但它却真的是linuxCPU负载均衡的核心,不过实际的算法在此基础上有很多细化。对于Intel的CPU,压缩在同一个chip上的多核是共享同一个L2的(如下图,里面的一个Processor其实就是一个chip),如果任务能尽可能的分配在同一个chip上,L2cache就可以继续使用,这对运行速度是有帮助的。所以除非“很不均衡”,否则尽量不要把一个chip上的任务挪到其他chip上。于是,为了应对这种CPUcore之间的异质性在不同的core之间迁移任务,代价不同Linuxkernel引入了sched_domain和sched_group的概念。sched_domain和sched_group的具体原理,可参考刘勃的文章和英文资料。【代码剖析】SMP负载均衡检查或调整在两个内核函数里发生:1.schedule()。当进程调用了sleep、usleep、poll、epoll、pause时,也就是调用了可能睡去的操作时都会转为内核代码里对schedule()函数的调用。2.try_to_wake_up()。说白了就是进程刚才睡了,现在要醒来,那醒来以后跑在哪个CPU上呢?这个选择CPU的过程,也就是负载均衡的过程。我们先看schedule()的代码,我们忽略函数前面那些和负载均衡无关的代码(本文代码以内核2.6.20版为准):[kernel/sched.c-->schedule()]3489cpu=smp_processor_id();3490if(unlikely(!rq->nr_running)){3491idle_balance(cpu,rq);3492if(!rq->nr_running){3493next=rq->idle;3494rq->expired_timestamp=0;3495wake_sleeping_dependent(cpu);3496gotoswitch_tasks;3497}3498}每个CPU都有一个运行队列即这里的rq,运行队列里放着该CPU要运行的进程,如果运行队列里没有进程了,就说明当前CPU没有可调度的任务了,那就要调用idle_balance从其它CPU上“平衡”一些(就是挪一些)进程到当前rq里。再看idle_balance()的实现:[kernel/sched.c-->idle_balance()]2806/*2807*idle_balanceiscalledbyschedule()ifthis_cpuisabouttobecome2808*idle.AttemptstopulltasksfromotherCPUs.2809*/2810staticvoididle_balance(intthis_cpu,structrq*this_rq)2811{2812structsched_domain*sd;2813intpulled_task=0;2814unsignedlongnext_balance=jiffies+60*HZ;28152816for_each_domain(this_cpu,sd){2817unsignedlonginterval;28182819if(!(sd->flags&SD_LOAD_BALA