1、非正在运行的普通进程变成实时进程时(比如通过sched_setscheduler系统调用);
2、发生调度之后(这时候可能有一个实时进程被更高优先级的实时进程抢占了);
3、实时进程被唤醒之后,如果不能马上在当前CPU上运行(它不是当前CPU上优先级最高的进程);
看起来,实时进程的负载均衡对于每个CPU一个run_queue这种模式似乎有些别扭,每次需要选择一个实时进程,总是需要遍历所有run_queue,在尚未能得到运行的实时进程之中找到优先级最高的那一个 。其实,如果所有CPU共用同一个run_queue,就没有这么多的烦恼了 。为什么不这样做呢?
1、在CPU对run_queue的竞争方面,“每个CPU去竞争每一个run_queue”比“每个CPU去竞争一个总的run_queue”略微好一些,因为竞争的粒度更小了;
2、在进程的移动方面,每个CPU一个run_queue这种模式其实也不能很好的把进程留在同一个CPU上,因为严格的优先级关系使得进程必须在出现不均衡时立刻被移动 。不过,一些特殊情况下进程的迁移还是有一定选择面的 。比如优先级相同的时候就可以尽量不做迁移、push_rt_task的时候可以选择跟当前CPU最为亲近的CPU去迁移 。
普通进程的负载均衡可以看出,实时进程的负载均衡性能是不会太好的 。为了满足严格的优先级关系,丝毫的不均衡都是不能容忍的 。所以一旦top-N的平衡关系发生变化,内核就必须即时完成负载均衡,形成新的top-N的平衡关系 。这可能会使得每个CPU频繁去竞争run_queue、进程频繁被迁移 。
而普通进程则并不要求严格的优先级关系,可以容忍一定程度的不均衡 。所以普通进程的负载均衡可以不必在进程发生变化时即时完成,而采用一些异步调整的策略 。
普通进程的负载均衡在以下情况下会被触发:
1、当前进程离开TASK_RUNNING状态(进入睡眠或退出),而对应的run_queue中已无进程可用时 。这时触发负载均衡,试图从别的run_queue中pull一个进程过来运行;
2、每隔一定的时间,启动负载均衡过程,试图发现并解决系统中不均衡;
另外,对于调用exec的进程,它的地址空间已经完全重建了,当前CPU上已经不会再缓存对它有用的信息 。这时内核也会考虑负载均衡,为它们找一个合适的CPU 。
那么,对于普通进程来说,“均衡”到底意味着什么呢?
在单CPU环境下,处于TASK_RUNNING状态的进程会以其优先级为权重,瓜分CPU时间 。优先级越高的进程,权重越高,分得的CPU时间也就越多 。在CFS调度(完全公平调度,针对普通进程的调度程序)中,这里的权重被称作load 。假设某个进程的load为m,所有处于TASK_RUNNING状态的进程的load之和为M,那么这个进程所能分到的CPU时间是m/M 。比如系统中有两个TASK_RUNNING状态的进程,一个load为1、一个load为2,总的load是1+2=3 。则它们分到的CPU时间分别是1/3和2/3 。
推广到SMP环境,假设有N个CPU,那么一个load为m的进程所能分到的CPU时间应该是N*m/M(如果不是,则要么这个进程挤占了别的进程的CPU时间、要么是被别的进程挤占) 。对于普通进程来说,这就是所谓的“均衡” 。
那么,如何让进程能够分到N*m/M的CPU时间呢?其实,只需要把所有进程的load平分到每一个run_queue上,使得每个run_queue的load(它上面的进程的load之和)都等于M/N,这样就好了 。于是,每个run_queue的load就成了是否“均衡”的判断依据 。
下面看看load_balance里面做些什么 。注意,不管load_balance是怎样被触发的,它总是在某个CPU上被执行 。而load_balance过程被实现得非常简单,只需要从最繁忙(load最高)的run_queue中pull几个进程到当前run_queue中(只pull,不push),使得当前run_queue与最繁忙的run_queue得到均衡(使它们的load接近于所有run_queue的平均load),仅此而已 。load_balance并不需要考虑所有run_queue全局的均衡,但是当load_balance在各个CPU上分别得到运行之后,全局的均衡也就实现了 。这样的实现极大程度减小了负载均衡的开销 。
load_balance的过程大致如下:
1、找出最繁忙的一个run_queue;
2、如果找到的run_queue比本地run_queue繁忙,且本地run_queue的繁忙程度低于平均水平,那么迁移几个进程过来,使两个run_queue的load接近平均水平 。反之则什么都不做;
在比较两个run_queue繁忙程度的问题上,其实是很有讲究的 。这个地方很容易想当然地理解为:把run_queue中所有进程的load加起来,比较一下就OK了 。而实际上,需要比较的往往并不是实时的load 。
推荐阅读
- 浅谈在Linux中如何将脚本做成系统服务开机自启动
- Linux服务器磁盘满了怎么办
- linux安装php步骤详解
- 「linux专栏」top命令用法详解,再也不怕看不懂top了
- 从命令行查看所有已安装的Linux内核
- Linux再次被爆root提权漏洞,已存在长达15年
- 获取linux内存、cpu、磁盘IO等信息shell脚本及其原理详解
- linux命令删除目录下所有文件?linux怎么删除目录下的文件
- 一篇文章讲清Linux操作系统的目录结构
- 检查Linux内存占用的 5 大命令,你知道几个?