一文读懂 | CPU负载均衡实现

发表于 3年以前  | 总阅读数:342 次

在《[一文读懂 | 进程怎么绑定 CPU] 》这篇文章中介绍过,在 Linux 内核中会为每个 CPU 创建一个可运行进程队列,由于每个 CPU 都拥有一个可运行进程队列,那么就有可能会出现每个可运行进程队列之间的进程数不一样的问题,这就是所谓的 负载不均衡 问题,如下图所示:

(图1)

最极端的情况是,一个 CPU 的可运行进程队列拥有非常多的进程,而其他 CPU 的可运行进程队列为空,这就是著名的 一核有难,多核围观,如下图:

(图2)

为了避免这个问题的出现,Linux 内核实现了 CPU 可运行进程队列之间的负载均衡。接下来,我们将会介绍 CPU 间的负载均衡的实现原理。

本文使用的内核版本为:Linux-2.6.23

CPU 间负载均衡原理

CPU 间负载不均衡的根本原因就是,CPU 的可运行进程队列中的进程数量不均衡导致的。所以,要解决 CPU 间负载不均衡的方法就是:将最繁忙的 CPU 可运行进程队列的一些进程迁移到其他比较空闲的 CPU 中,从而达到 CPU 间负载均衡的目的。

当然,在 2.6.0 版本的内核的确是这样实现的,我们可以看看其实现代码:

static void 
load_balance(runqueue_t *this_rq, int idle, cpumask_t cpumask)
{
    int imbalance, idx, this_cpu = smp_processor_id();
    runqueue_t *busiest;
    prio_array_t *array;
    struct list_head *head, *curr;
    task_t *tmp;

    // 1. 找到最繁忙的 CPU 运行队列
    busiest = find_busiest_queue(this_rq, this_cpu, idle, &imbalance, cpumask);
    if (!busiest)
        goto out;
    ...

    head = array->queue + idx;
    curr = head->prev;

skip_queue:
    // 2. 从最繁忙运行队列中取得一个进程
    tmp = list_entry(curr, task_t, run_list);
    ...

    // 3. 把进程从最繁忙的可运行队列中迁移到当前可运行队列中
    pull_task(busiest, array, tmp, this_rq, this_cpu);
    ...
}

load_balance 函数主要用于解决 CPU 间负载均衡问题,其主要完成以下 3 个步骤:

  • 从所有 CPU 的可运行队列中找到最繁忙的可运行队列。
  • 从最繁忙可运行队列中取得一个进程。
  • 把进程从最繁忙的可运行队列中迁移到当前可运行队列中。

这是 2.6.0 版本的解决方案,但这个方案并不是最优的,因为现代 CPU 架构是非常复杂的,比如一个物理 CPU 有多个核心(多核),而每个核心又可以通过超线程(Hyper-Threading)来实现多个逻辑 CPU,如下图所示:

(图3)

如上图所示,一个物理 CPU 中拥有 4 个核心,而每个核心又拥有 2 个超线程。在 Linux 内核中,会为每个超线程定义一个可运行进程队列,所以 Linux 内核会为上面的 CPU 定义 8 个可运行进程队列。

现在问题来了,在上面的 CPU 架构中,不同的可运行队列之间的进程迁移代价是不一样的。因为同一个核心的不同超线程共用了所有的缓存,所以同一个核心不同超线程间的进程迁移代价是最小的。

而同一个物理 CPU 不同核心间也会共用某些缓存,所以不同核心间的进程迁移的代价会比同一核心不同超线程间的进程迁移稍大。由于现在很多主板都支持安装多个物理 CPU,而不同物理 CPU 间基本不会共用缓存,所以不同物理 CPU 间的进程迁移代价最大。如下图所示(图中的 L1、L2 和 L3 分别指一级、二级和三级缓存):

(图4)

为了解决进程迁移成本的问题,新版本的 Linux 内核引入了 调度域调度组

调度域与调度组

从前面的分析可知,根据 CPU 的物理架构可以划分为:不同的物理 CPU、相同 CPU 不同的核心、相同核心不同的超线程等,如下图所示:

(图5)

在 Linux 内核中,把这个层级成为 调度域。从前面的分析可知,越下层的调度域共用的缓存就越多,所以在进程迁移时,优先从底层的调度域开始进行。

由于内核为每个超线程定义一个可运行队列,所以图 3 中的 CPU 拥有 8 个可运行队列。而根据不同的调度域,可以把这 8 个可运行队列划分为不同的 调度组,如下图所示:

(图6)

如上图所示,由于每个超线程都拥有一个可运行队列,所以图 3 的 CPU 拥有 8 个可运行队列,而这些可运行队列可以根据不同的核心来划分为 4 个调度组,而这 4 个调度组可以根据不同的物理 CPU 来划分成 1 个调度组。

由于越底层的调度域共用的缓存越多,所以对 CPU 可运行队列进行负载均衡时,优先从底层调度域开始。比如把 Thread0 可运行队列的进程迁移到 Thread1 可运行队列的代价要比迁移到 Thread2 可运行队列的小,这是由于 Thread0 与 Thread1 属于同一个核心,同一个核心共用所有的 CPU 缓存。

在 Linux 内核中,调度域使用 sched_domain 结构表示,而调度组使用 sched_group 结构表示。我们来看看 sched_domain 结构的定义:

struct sched_domain {
    struct sched_domain *parent;    /* top domain must be null terminated */
    struct sched_domain *child;     /* bottom domain must be null terminated */
    struct sched_group  *groups;    /* the balancing groups of the domain */
    cpumask_t            span;      /* span of all CPUs in this domain */
    ...
};

下面介绍一下 sched_domain 结构各个字段的作用:

  • parent:由于调度域是分层的,上层调度域是下层的调度域的父亲,所以这个字段指向的是当前调度域的上层调度域。
  • child:如上所述,这个字段用来指向当前调度域的下层调度域。
  • groups:每个调度域都拥有一批调度组,所以这个字段指向的是属于当前调度域的调度组列表。
  • span:这个字段主要用来标记属于当前调度域的 CPU 列表(每个位表示一个 CPU)。

我们接着分析一下 sched_group 结构,其定义如下:

struct sched_group {
    struct sched_group *next;
    cpumask_t           cpumask;
    ...
};

下面介绍一下 sched_group 结构各个字段的作用:

  • next:指向属于同一个调度域的下一个调度组。
  • cpumask:用于标记属于当前调度组的 CPU 列表(每个位表示一个 CPU)。

它们之间的关系如下图所示:

(图7)

CPU 间负载均衡实现

要实现 CPU 间的负载均衡,只需要将最繁忙的可运行队列中的一部分进程迁移到空闲的可运行队列中即可。但由于 CPU 缓存的原因,对使用不同的 CPU 缓存的可运行队列之间进行进程迁移,将会导致缓存丢失,从而导致性能损耗。所以,Linux 内核会优先对使用相同 CPU 缓存的可运行队列之间进行进程迁移。

1. CPU 间负载均衡触发时机

当 CPU 的负载不均衡时,内核就需要对 CPU 进行负载均衡。负载均衡的触发时机比较多,如进程被创建、进程被唤醒、进程休眠和时钟中断等,这里我们介绍一下在时钟中断时怎么进行 CPU 间的负载均衡。

在 Linux 内核中是通过 rq 结构来描述一个可运行进程队列的,它有个名为 sd 的字段用于指向其所属的 调度域 层级的最底层,如下所示:

struct rq {
    ...
    struct sched_domain *sd;
    ...
}

它与调度域和调度组的关系如下图所示:

(图8)

在时钟中断下半部处理中,会通过调用 run_rebalance_domains 函数来对 CPU 进行负载均衡处理,而 run_rebalance_domains 接着会通过调用 rebalance_domains 函数来完成负载均衡的工作,其实现如下:

static inline void 
rebalance_domains(int cpu, enum cpu_idle_type idle)
{
    int balance = 1;
    struct rq *rq = cpu_rq(cpu);
    unsigned long interval;
    struct sched_domain *sd;
    unsigned long next_balance = jiffies + 60*HZ;
    int update_next_balance = 0;

    // 遍历可运行队列的调度组层级 (从最底层开始)
    for_each_domain(cpu, sd) {
        ...
        // 由于对 CPU 进行负载均衡可能会导致 CPU 缓存丢失
        // 所以对 CPU 进行负载均衡不能太频繁, 必须隔一段时间才能进行
        // 这里就是判断上次进行负载均衡与这次的间隔是否已经达到合适的时间
        // 如果时间间隔已经达到一段时间, 那么就调用 load_balance 函数进行负载均衡
        if (time_after_eq(jiffies, sd->last_balance + interval)) {
            if (load_balance(cpu, rq, sd, idle, &balance)) {
                idle = CPU_NOT_IDLE;
            }
            sd->last_balance = jiffies;
        }
        ...
    }
    ...
}

由于每个 CPU(超线程)都有一个可运行队列,而 rebalance_domains 函数的工作就是获取当前 CPU (超线程)的可运行队列,然后从最底层开始遍历其调度域层级(由于越底层的调度域,进行进程迁移的代价越小)。

由于对 CPU 进行负载均衡可能会导致 CPU 缓存丢失,所以对 CPU 进行负载均衡不能太频繁(需要隔一段时间才能进行)。那么在对 CPU 进行负载均衡前,就需要判断上次进行负载均衡与这次的时间间隔是否合理。如果时间间隔合理, 那么就调用 load_balance 函数对调度域进行负载均衡。

load_balance 函数实现如下:

static int
load_balance(int this_cpu, struct rq *this_rq, struct sched_domain *sd,
             enum cpu_idle_type idle, int *balance)
{
    ...

redo:
    // 1. 从调度域中找到一个最繁忙的调度组
    group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
                               &cpus, balance);
    ...

    // 2. 从最繁忙的调度组中找到一个最繁忙的运行队列
    busiest = find_busiest_queue(group, idle, imbalance, &cpus);
    ...

    if (busiest->nr_running > 1) {
        ...
        // 3. 从最繁忙的运行队列中迁移一些任务到当前任务队列
        ld_moved = move_tasks(this_rq, this_cpu, busiest, imbalance, sd, idle,
                              &all_pinned);
        ...
    }
    ...
    return 0;
}

load_balance 函数主要完成 3 个工作:

  • 调度域 中找到一个最繁忙的 调度组
  • 从最繁忙的 调度组 中找到一个最繁忙的 可运行队列
  • 从最繁忙的 可运行队列 中迁移一些任务到当前 可运行队列

这样就完成了 CPU 间的负载均衡处理。

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/668EIM3opj9uwWoMz3CEbA

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 6年以前  |  237375次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8244次阅读
 目录