什么是负载均衡?
为了CPU之间减少“干扰”,每个CPU上都有一个任务队列。运行的过程种可能会出现有的CPU“忙的一笔”,有的CPU“闲的蛋疼”,于是便需要负载均衡。
将task从负载较重的CPU上转移到负载相对较轻的CPU上执行,这个过程就是负载均衡的过程。
在了解负载均衡前有必要了解soc上对CPU的拓扑关系。
我们知道一个多核心的soc片上系统,内部结构是很复杂的,内核采用CPU拓扑结构来描述一个SOC的架构。内核使用调度域来描述CPU之间的层次关系,对于低级别的调度域来说,CPU之间的负载均衡处理开销比较小,而对于越高级别的调度域,其负载均衡的开销就越大。
比如一个4核心的SOC,两个核心是一个cluster,共享L2 cache,那么每个cluster可以认为是一个MC调度域,每个MC调度域中有两个调度组,每个调度组中只有一个CPU。而整个SOC可以认为是高一级别的DIE调度域,其中有两个调度组,cluster0属于一个调度组,cluster1属于另一个调度组。跨cluster的负载均衡是需要清除L2 cache的,开销是很大的,因此SOC级别的DIE调度域进行负载均衡的开销会更大一些。
CPU对应的调度域和调度组可通过在设备模型文件 /proc/sys/kernel/sched_domain 里查看。
调度域 sched_domain 主要的成员如下:
调度组 sched_group 主要的成员如下:
CPU拓扑示例
为了减少锁的竞争,每一个cpu都有自己的MC domain、DIE domain(sched domain是分成两个level,base domain称为MC domain(multi core domain),顶层的domain称为DIE domain)以及sched group,并且形成了sched domain之间的层级结构,sched group的环形链表结构。可以通过/sys/devices/system/cpu/cpuX/topology查看cpu topology信息。
在上面的结构中,sched domain是分成两个level,base domain称为MC domain,顶层的domain称为DIE domain。顶层的DIE domain覆盖了系统中所有的CPU,小核cluster的MC domain包括所有小核cluster中的cpu,大核cluster的MC domain包括所有大核cluster中的cpu。
通过DTS和CPU topo子系统,可以构建sched domain层级结构,用于具体的均衡算法。流程是:kernel_init() -> kernel_init_freeable() -> smp_prepare_cpus() -> init_cpu_topology() -> parse_dt_topology()
【文章福利】另外小编还整理了一些C++后端开发面试题,教学视频,后端学习路线图免费分享,需要的可以自行添加:学习交流群点击加入~ 群文件共享
小编强力推荐C++后端开发免费学习地址:C/C++Linux服务器开发高级架构师/C++后台开发架构师/course/417774?flowToken=1013189
负载均衡的软件架构
图中可以看出左边主要分为CPU负载跟踪和task负载跟踪。
CPU负载跟踪:考虑每一个CPU的负载。汇聚cluster上所有负载,方便计算cluster之间负载的不均衡状况。
task负载跟踪:判断该任务是否适合当前CPU算力。如果判定需要均衡,那么需要在CPU之间迁移多少的任务才能达到平衡。
右边是通过DTS和CPU topo子系统,构建的sched domain层级结构。流程是:kernel_init() -> kernel_init_freeable() -> smp_prepare_cpus() -> init_cpu_topology() -> parse_dt_topology()
有了左右两边的基础设施,那么什么时候触发负载均衡呢?这主要和调度事件相关,当发生任务唤醒、任务创建、tick到来等调度事件的时候,就可以检查当前系统的不均衡情况,并酌情进行任务迁移,以便让系统负载处于平衡状态。
何时做负载均衡?
CFS任务的负载均衡器有两种。一种是为繁忙CPU们准备的periodic balancer,用于CFS任务在busy cpu上的均衡;一种是为idle cpu们准备的idle balancer,用于把繁忙CPU上的任务均衡到idle cpu上来。
周期性负载均衡(periodic load balance或者tick load balance)是指在tick中,周期性的检测系统的负载均衡状况,找到系统中负载最重的domain、group和CPU,将其上的runnable任务拉到本CPU以便让系统的负载处于均衡的状态。
nohz load balance是指其他的cpu已经进入idle,本CPU任务太重,需要通过 IPI 将其他idle的CPUs唤醒来进行负载均衡。nohz idle load balance也是通过busy cpu上tick驱动的,如果需要kick idle load balancer,那么就会通过GIC发送一个ipi中断给选中的idle cpu,让它代表系统所有的idle cpu们进行负载均衡。
new idle load balance 比较好理解,就是在CPU上没有任务执行,马上要进入idle状态的时候,看看其他CPU是否需要帮忙,来从busy cpu上拉任务,让整个系统的负载处于均衡状态。
负载均衡的基本过程
当一个CPU上进行负载均衡的时候,总是从base domain开始,检查其所属sched group之间的负载均衡情况,如果有不均衡情况,那么会在该cpu所属cluster之间进行迁移,以便维护cluster内各个cpu core的任务负载均衡。
load_balance是处理负载均衡的核心函数,它的处理单元是一个调度域,也就是sched domain,其中会包含对调度组的处理。
在该domain中找到最忙的sched group
在最忙的group中挑选最忙的CPU runqueue,该CPU就成为任务迁移的src
从该队列中选择要迁移的任务(判断的依据主要是task load的大小,优先选择load重的任务)
向着作为dst的CPU runqueue迁移
参考资料
推荐一个零声教育C/C++后台开发的免费公开课程,个人觉得老师讲得不错,分享给大家:C/C++后台开发高级架构师,内容包括Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习
原文:Linux 进程管理之CFS负载均衡
如果觉得《深入理解Linux 进程管理之CFS负载均衡》对你有帮助,请点赞、收藏,并留下你的观点哦!