2.8.1 简介

由于调度器的运行队列(runqueue)是per-cpu的,那么在一个多核系统中,就可能出现各CPU的负载不均衡的情况,如果一个CPU的队列被塞得满满当当,而另一个CPU的队列里空空如也,那肯定是不可取的。为了避免这种情况,调度器就还必须处理好多核之间的负载均衡。

通过PELT, 系统对负载的跟踪可以精确到每个调度实体,这为调度器完成负载均衡提供了数据支持。如果我们只考虑最简单的模型,那么调度器只需要随时跟踪每个CPU队列的总负载,然后将高负载CPU队列中的任务酌情迁移一些到低负载的CPU队列中,尽量保持每个CPU队列的负载总量相等即可。

但任务的迁移是有代价的,这个代价一方面是选择目标CPU的时间开销,一方面是任务迁移带来的性能损耗。负载均衡的目的是提升系统整体的效率,但如果策略不当,有可能反而会对系统的性能产生影响。如何高效地达成这件事情,是系统设计者需要面临的挑战。在本节中,我们将从如下方面对CFS的负载均衡进行讨论:

  • CPU的拓扑结构 由于不同的CPU对缓存(L1, L2, L3)的共享级别不同,甚至对对内存的访问效率也不同(NUMA),因此会导致任务的迁移代价也不同。我们会简要介绍SMP, NUMA这两种拓扑结构。

  • 核心数据结构 内核如何根据CPU的物理拓扑结构在内核中对其进行组织管理,将会涉及到调度域(sched domain)与调度组(sched group)的概念。

  • 负载均衡的核心逻辑 涉及到负载均衡的核心数据结构与算法思路,包括主要的函数以及实现方式

  • 负载均衡的时机 不同场景下系统如何触发负载均衡

Last updated