加入收藏 | 设为首页 | 会员中心 | 我要投稿 财气旺网 - 财气网 (https://www.caiqiwang.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Windows > 正文

Linux内核的进程负载均衡机制

发布时间:2019-04-12 09:24:51 所属栏目:Windows 来源:金庆辉
导读:概述 在多核系统中,为了更好的利用多CPU并行能力,进程调度器可以将进程负载尽可能的平均到各个CPU上。再具体实现中,如何选择将进程迁移到的目标CPU,除了考虑各个CPU的负载平衡,还需要将Cache利用纳入权衡因素。同时,对于进程A唤醒进程B这个模型,还

以下是rebalance_domains()函数核心流程,值得注意的是,每个层级的调度间隔不是固定的,而是临时计算出来,他在一个可通过proc接口配置的最小值和最大值之间。

Linux内核的进程负载均衡机制

以下是对CPU的每个层级调度域调用load_balance()函数核心流程,目的是把一些进程迁移到指定的CPU(该场景就是当前CPU)。

Linux内核的进程负载均衡机制

以我的服务器为例,观察不同层级调度域的调度间隔范围,时间单位为jiffies。

可见,SMT负载均衡频率最高,越往上层越低。这也符合体系结构特点,在越低层次迁移进程代价越小(Cache利用率高),所以可以更加频繁一点。

CPU进入idle前负载均衡

当进程调度函数__schedule()把即将切换到idle进程前,会发生一次负载均衡来避免当前CPU空闲。

  1. static void __sched __schedule(void) 
  2.         ... 
  3.         if (unlikely(!rq->nr_running)) 
  4.                 idle_balance(cpu, rq); 
  5.  
  6.         ... 

核心函数idle_balance()。基本上也是尽可能在低层调度域中负载均衡。

  1. /*  * idle_balance is called by schedule() if this_cpu is about to become  * idle. Attempts to pull tasks from other CPUs.  */ 
  2. void idle_balance(int this_cpu, struct rq *this_rq) 
  3.     unsigned long next_balance = jiffies + HZ; 
  4.     struct sched_domain *sd; 
  5.     int pulled_task = 0; 
  6.     u64 curr_cost = 0; 
  7.  
  8.     this_rq->idle_stamp = rq_clock(this_rq); 
  9.  
  10.     /* 如果该CPU平均空闲时间小于/proc中的配置值或者该cpu调度域中所有cpu都是idle状态,那么不需要负载均衡了*/ 
  11.     if (this_rq->avg_idle < sysctl_sched_migration_cost || 
  12.         !this_rq->rd->overload) { 
  13.         rcu_read_lock(); 
  14.         sd = rcu_dereference_check_sched_domain(this_rq->sd); 
  15.         if (sd) 
  16.             update_next_balance(sd, 0, &next_balance); 
  17.         rcu_read_unlock(); 
  18.  
  19.         goto out; 
  20.     } 
  21.  
  22.     /*   * Drop the rq->lock, but keep IRQ/preempt disabled.     */ 
  23.     raw_spin_unlock(&this_rq->lock); 
  24.  
  25.     update_blocked_averages(this_cpu); 
  26.     rcu_read_lock(); 
  27.     /* 从底向上遍历调度域,只要迁移成功一个进程就跳出循环*/ 
  28.     for_each_domain(this_cpu, sd) { 
  29.         int should_balance; 
  30.         u64 t0, domain_cost; 
  31.  
  32.         if (!(sd->flags & SD_LOAD_BALANCE)) 
  33.             continue; 
  34.  
  35.         /*           * 如果(当前累积的负载均衡开销时间 + 历史上该层级负载均衡开销最大值)已经大于CPU平均空闲时间了,          * 那么就没有必要负载均衡了。注意,sd->max_newidle_lb_cost会在load_balance()函数中缓慢减少。          */ 
  36.         if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) { 
  37.             update_next_balance(sd, 0, &next_balance); 
  38.             break; 
  39.         } 
  40.  
  41.         /* 我的机器上该标记总是设置了SD_BALANCE_NEWIDLE */ 
  42.         if (sd->flags & SD_BALANCE_NEWIDLE) { 
  43.             t0 = sched_clock_cpu(this_cpu); 
  44.  
  45.             pulled_task = load_balance(this_cpu, this_rq, 
  46.                            sd, CPU_NEWLY_IDLE, 
  47.                            &should_balance); 
  48.             
  49.             domain_cost = sched_clock_cpu(this_cpu) - t0; 
  50.             if (domain_cost > sd->max_newidle_lb_cost) 
  51.                 sd->max_newidle_lb_cost = domain_cost; 
  52.  
  53.            /* 记录了当前负载均衡开销累计值 */ 
  54.             curr_cost += domain_cost; 
  55.         } 
  56.  
  57.         update_next_balance(sd, 0, &next_balance); 
  58.  
  59.         /*       * Stop searching for tasks to pull if there are         * now runnable tasks on this rq.        */         
  60.         if (pulled_task || this_rq->nr_running > 0) { 
  61.             this_rq->idle_stamp = 0; 
  62.             break; 
  63.         } 
  64.     } 
  65.     rcu_read_unlock(); 
  66.  
  67.     raw_spin_lock(&this_rq->lock); 
  68.  
  69. out: 
  70.     /* Move the next balance forward */ 
  71.     if (time_after(this_rq->next_balance, next_balance)) 
  72.         this_rq->next_balance = next_balance; 
  73.  
  74.     if (curr_cost > this_rq->max_idle_balance_cost) 
  75.         this_rq->max_idle_balance_cost = curr_cost; 

其它需要用到SMP负载均衡模型的时机

(编辑:财气旺网 - 财气网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!