# 2.8.1 简介

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

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

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

* CPU的拓扑结构 \
  由于不同的CPU对缓存（L1, L2, L3）的共享级别不同，甚至对对内存的访问效率也不同（[NUMA](https://en.wikipedia.org/wiki/Non-uniform_memory_access)），因此会导致任务的迁移代价也不同。我们会简要介绍SMP, [NUMA](https://en.wikipedia.org/wiki/Non-uniform_memory_access)这两种拓扑结构。
* 核心数据结构 \
  内核如何根据CPU的物理拓扑结构在内核中对其进行组织管理，将会涉及到调度域（sched domain）与调度组（sched group）的概念。
* 负载均衡的核心逻辑 \
  涉及到负载均衡的核心数据结构与算法思路，包括主要的函数以及实现方式
* 负载均衡的时机 \
  不同场景下系统如何触发负载均衡
