V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
jerry017cn
V2EX  ›  Linux

Cgroup - 从 CPU 资源隔离说起(三)

  •  
  •   jerry017cn · 2015-12-28 22:42:21 +08:00 · 5807 次点击
    这是一个创建于 3034 天前的主题,其中的信息可能已经有所发展或是发生改变。

    权重 CPU 资源隔离

    这里的权重其实是 shares 。我把它叫做权重是因为这个值可以理解为对资源占用的权重。这种资源隔离方式事实上也是对 cpu 时间的进行分配。区别是作用在 cfs 调度器的权重值上。从用户的角度看,无非就是给每个 cgroup 配置一个 share 值, cpu 在进行时间分配的时候,按照 share 的大小比率来确定 cpu 时间的百分比。它对比 cpuquota 的优势是,当进程不在 cfs 可执行调度队列中的时候,这个权重是不起作用的。就是说,一旦其他 cgroup 的进程释放 cpu 的时候,正在占用 cpu 的进程可以全占所有计算资源。而当有多个 cgroup 进程都要占用 cpu 的时候,大家按比例分配。

    我们照例通过实验来说明这个情况,配置方法也很简单,修改 cgconfig.conf ,添加字段,并重启服务:

    group zorro {
        cpu {
                cpu.shares = 1000;
        }
    }
    
    [root@zorrozou-pc ~]# service cgconfig restart
    

    配置完之后,我们就给 zorro 组配置了一个 shares 值为 1000 ,但是实际上如果系统中只有这一个组的话, cpu 看起来对他是没有限制的。现在的执行效果是这样:

    [root@zorrozou-pc ~]# mpstat -P ALL 1
    
    17:17:29     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
    17:17:30     all   99.88    0.00    0.12    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       2  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       3   99.01    0.00    0.99    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       4   99.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       5  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       6  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       7  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       8  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30       9  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      10  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      11  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      12  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      13  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      14  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      15  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      16  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      17   99.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      18  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      19  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      20  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      21  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      22  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    17:17:30      23  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
    
    [zorro@zorrozou-pc ~/test]$ time ./prime_thread_zorro &> /dev/null
    
    real    0m8.937s
    user    3m32.190s
    sys 0m0.225s
    

    如显示, cpu 我们是独占的。那么什么时候有隔离效果呢?是系统中有别的 cgroup 也要占用 cpu 的时候,就能看出效果了。比如此时我们再添加一个 jerry , shares 值也配置为 1000 ,并且让 jerry 组一直有占用 cpu 的进程在运行。

    group jerry {
        cpu {
                cpu.shares = "1000";
        }
    }
    
    
    top - 17:24:26 up 1 day, 5 min,  2 users,  load average: 41.34, 16.17, 8.17
    Tasks: 350 total,   2 running, 348 sleeping,   0 stopped,   0 zombie
    Cpu0  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu1  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu2  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu3  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu4  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu5  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu6  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu7  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu8  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu9  : 99.7%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.3%hi,  0.0%si,  0.0%st
    Cpu10 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu11 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu12 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu13 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu14 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu15 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu16 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu17 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu18 : 99.3%us,  0.7%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu19 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu20 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu21 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu22 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu23 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  131904480k total,  4938020k used, 126966460k free,   136140k buffers
    Swap:  2088956k total,        0k used,  2088956k free,  3700480k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                               
    13945 jerry     20   0  390m  872  392 S 2397.2  0.0  48:42.54 jerry
    

    我们以 jerry 用户身份执行了一个进程一直 100%占用 cpu ,从上面的显示可以看到,这个进程占用了 2400%的 cpu ,是因为每个 cpu 核心算 100%, 24 个核心就是 2400%。此时我们再以 zorro 身份执行筛质数的程序,并察看这个程序占用 cpu 的百分比:

    top - 19:44:11 up 1 day,  2:25,  3 users,  load average: 60.91, 50.92, 48.85
    Tasks: 336 total,   3 running, 333 sleeping,   0 stopped,   0 zombie
    Cpu0  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu1  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu2  : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu3  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu4  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu5  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu6  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu7  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu8  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu9  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu10 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu11 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu12 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu13 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu14 : 99.7%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.3%hi,  0.0%si,  0.0%st
    Cpu15 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu16 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu17 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu18 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu19 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu20 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu21 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu22 : 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu23 :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  131904480k total,  1471772k used, 130432708k free,   144216k buffers
    Swap:  2088956k total,        0k used,  2088956k free,   322404k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                               
    13945 jerry     20   0  390m  872  392 S 1200.3  0.0   3383:04 jerry                                                                                                                                               
     9311 zorro     20   0  390m  872  392 R 1197.0  0.0   0:51.56 prime_thread_zo
    

    通过 top 我们可以看到,以 zorro 用户身份执行的进程和 jerry 进程平分了 cpu ,每人 50%。 zorro 筛质数执行的时间为:

    [zorro@zorrozou-pc ~/test]$ time ./prime_thread_zorro &> /dev/null
    
    real    0m15.152s
    user    2m58.637s
    sys 0m0.220s
    [zorro@zorrozou-pc ~/test]$ time ./prime_thread_zorro &> /dev/null
    
    real    0m15.465s
    user    3m0.706s
    sys 0m0.221s
    

    根据这个时间看起来,基本与通过 cpuquota 方式分配 50%的 cpu 时间以及通过 cpuset 方式分配 12 个核心的情况相当,而且效率还稍微高一些。当然我要说明的是,这里几乎两秒左右的效率的提高并不具备很大的参考性,它与 jerry 进程执行的运算是有很大相关性的。此时 jerry 进程执行的是一个多线程的 while 死循环,占满所有 cpu 跑。当我们把 jerry 进程执行的内容同样变成筛质数的时候, zorro 用户的进程执行效率的参考值就比较标准了:

    [zorro@zorrozou-pc ~/test]$ time ./prime_thread_zorro &> /dev/null
    
    real    0m17.521s
    user    3m32.684s
    sys 0m0.254s
    [zorro@zorrozou-pc ~/test]$ time ./prime_thread_zorro &> /dev/null
    
    real    0m17.597s
    user    3m32.682s
    sys 0m0.253s
    

    如程序执行显示,执行效率基本与 cpuset 和 cpuquota 相当。

    这又引发了另一个问题请大家思考:为什么 jerry 用户执行的运算的逻辑不同会影响 zorro 用户的运算效率?

    我们可以将刚才 cpuset 和 cpuquota 的对比列表加入 cpushare 一列来一起对比了,为了方便参考,我们都以 cpuset 为基准进行比较:

    shares zorro/shares jerry (核心数) cpuset realtime cpushare realtime cpuquota realtime
    2000/22000(2) 1m46.557s 1m41.691s 1m36.786s
    4000/20000(4) 0m53.271s 0m51.801s 0m51.067s
    6000/18000(6) 0m35.528s 0m35.152s 0m34.539s
    8000/16000(8) 0m26.643s 0m26.372s 0m25.923s
    12000/12000(12) 0m17.839s 0m17.694s 0m17.347s
    16000/8000(16) 0m13.384s 0m13.388s 0m13.015s
    24000/0(24) 0m8.972s 0m8.943s 0m8.932s

    请注意一个问题,由于 cpushares 无法像 cpuquota 或者 cpuset 那样只执行 zorro 用户的进程,所以在进行 cpushares 测试的时候,必须让 jerry 用户同时执行相同的筛质数程序,才能使两个用户分别分到相应比例的 cpu 时间。这样可能造成本轮测试结果的不准确。通过对比看到,当比率分别都配置了相当于两个核心的计算能力的情况下,本轮测试是 cpuquota 方式消耗了 1m36.786s 稍快一些。为了保证相对公平的环境作为参照,我们将重新对这轮测试进行数据采集,这次在 cpuset 和 cpuquota 的压测时,都用 jerry 用户执行一个干扰程序作为参照,重新分析数据。当然, cpushares 的测试数据就不必重新测试了:

    shares zorro/shares jerry (核心数) cpuset realtime cpushare realtime cpuquota realtime
    2000/22000(2) 1m46.758s 1m41.691s 1m42.341s
    4000/20000(4) 0m53.340s 0m51.801s 0m51.512s
    6000/18000(6) 0m35.525s 0m35.152s 0m34.392s
    8000/16000(8) 0m26.738s 0m26.372s 0m25.772s
    12000/12000(12) 0m17.793s 0m17.694s 0m17.256s
    16000/8000(16) 0m13.366s 0m13.388s 0m13.155s
    24000/0(24) 0m8.930s 0m8.943s 0m8.939s

    至此, cgroup 中针对 cpu 的三种资源隔离都介绍完了,分析我们的测试数据可以得出一些结论:

    1. 三种 cpu 资源隔离的效果基本相同,在资源分配比率相同的情况下,它们都提供了差不多相同的计算能力。
    2. cpuset 隔离方式是以分配核心的方式进行资源隔离,可以提供的资源分配最小粒度是核心,不能提供更细粒度的资源隔离,但是隔离之后运算的相互影响最低。需要注意的是在服务器开启了超线程的情况下,要小心选择分配的核心,否则不同 cgroup 间的性能差距会比较大。
    3. cpuquota 给我们提供了一种比 cpuset 可以更细粒度的分配资源的方式,并且保证了 cgroup 使用 cpu 比率的上限,相当于对 cpu 资源的硬限制。
    4. cpushares 给我们提供了一种可以按权重比率弹性分配 cpu 时间资源的手段:当 cpu 空闲的时候,某一个要占用 cpu 的 cgroup 可以完全占用剩余 cpu 时间,充分利用资源。而当其他 cgroup 需要占用的时候,每个 cgroup 都能保证其最低占用时间比率,达到资源隔离的效果。

    大家可以根据这三种不同隔离手段特点,针对自己的环境来选择不同的方式进行 cpu 资源的隔离。当然,这些手段也可以混合使用,以达到更好的 QOS 效果。

    但是可是 but ,这就完了么?
    显然并没有。。。。。。

    以上测试只针对了一种计算场景,这种场景在如此的简单的情况下,影响测试结果的条件已经很复杂了。如果是其他情况呢?我们线上真正跑业务的环境会这么单纯么?显然不会。我们不可能针对所有场景得出结论,想要找到适用于自己场景的隔离方式,还是需要在自己的环境中进行充分测试。在此只能介绍方法,以及针对一个场景的参考数据,仅此而已。单就这一个测试来说,它仍然不够全面,无法体现出内核 cpu 资源隔离的真正面目。众所周知, cpu 使用主要分两个部分, user 和 sys 。上面这个测试,由于测试用例的选择,只关注了 user 的使用。那么如果我们的 sys 占用较多会变成什么样呢?

    2 条回复    2015-12-31 20:35:25 +08:00
    virusdefender
        1
    virusdefender  
       2015-12-29 00:42:23 +08:00
    三篇大致的看完了,很棒~~
    Aydon0
        2
    Aydon0  
       2015-12-31 20:35:25 +08:00 via Android
    写的非常好,赞!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3516 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 00:08 · PVG 08:08 · LAX 17:08 · JFK 20:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.