容器实战高手课
李程远
eBay 总监级工程师,云平台架构师
24647 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 31 讲
容器实战高手课
15
15
1.0x
00:00/00:00
登录|注册

07 | Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?

实验:容器中运行CPU消耗进程,查看Load Average值
监控D状态进程
Load Average的计算公式
D状态进程导致性能下降
Load Average升高的原因
Load Average和CPU使用率的区别
Load Average的变化验证
Load Average的计算公式
Linux中的Load Average概念
Load Average值高,容器中进程运行慢
Linux系统维护中查看CPU使用情况
思考题
重点总结
现象解释:为什么Load Average会升高?
什么是Load Average?
问题再现
加了CPU Cgroup限制,为什么我的容器还是很慢?

该思维导图由 AI 生成,仅供参考

你好,我是程远。今天我想聊一聊平均负载(Load Average)的话题。
在上一讲中,我们提到过 CPU Cgroup 可以限制进程的 CPU 资源使用,但是 CPU Cgroup 对容器的资源限制是存在盲点的。
什么盲点呢?就是无法通过 CPU Cgroup 来控制 Load Average 的平均负载。而没有这个限制,就会影响我们系统资源的合理调度,很可能导致我们的系统变得很慢。
那么今天这一讲,我们要来讲一下为什么加了 CPU Cgroup 的配置后,即使保证了容器的 CPU 资源,容器中的进程还是会运行得很慢?

问题再现

在 Linux 的系统维护中,我们需要经常查看 CPU 使用情况,再根据这个情况分析系统整体的运行状态。有时候你可能会发现,明明容器里所有进程的 CPU 使用率都很低,甚至整个宿主机的 CPU 使用率都很低,而机器的 Load Average 里的值却很高,容器里进程运行得也很慢。
这么说有些抽象,我们一起动手再现一下这个情况,这样你就能更好地理解这个问题了。
比如说下面的 top 输出,第三行可以显示当前的 CPU 使用情况,我们可以看到整个机器的 CPU Usage 几乎为 0,因为"id"显示 99.9%,这说明 CPU 是处于空闲状态的。
但是请你注意,这里 1 分钟的"load average"的值却高达 9.09,这里的数值 9 几乎就意味着使用了 9 个 CPU 了,这样 CPU Usage 和 Load Average 的数值看上去就很矛盾了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了在使用CPU Cgroup限制容器资源后,容器中的进程仍可能运行缓慢的问题。作者首先介绍了Load Average的概念,指出它是Linux进程调度器中可运行队列的平均进程数目,与CPU Usage有所不同。通过实例验证了Load Average的影响,作者指出,即使容器内的进程CPU使用率较低,但Load Average值却很高,可能导致系统变得缓慢。文章还探讨了Load Average的计算方式及其与CPU Usage的差异,以及Load Average值升高导致应用性能下降的原因。此外,文章还介绍了Linux系统中Load Average的计算原理,包括可运行队列进程平均数和休眠队列中不可打断的进程平均数。通过对Load Average的解释和验证,读者能更好地理解CPU Cgroup限制对容器性能的影响。整体而言,本文深入浅出地解释了技术概念,对读者快速了解CPU Cgroup限制对容器性能影响具有指导意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《容器实战高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(20)

  • 最新
  • 精选
  • garnett
    请问老师,引入为 TASK_UNINTERRUPTIBLE 状态的进程的案例,top 输出中为什么wa使用率这一项没有增长?

    作者回复: TASK_UNINTERRUPTIBLE 状态的进程不一定是做I/O, 比如等待信号量的进程也会进入到这个状态。

    2020-11-30
    2
    17
  • 莫名
    推荐 stress 压测工具:stress -c 1 -t 600 平均负载计算公式(nr_active 表示单位时间内平均活跃进程个数,每个 CPU 对应一个 运行队列 rq,rq->nr_running、rq->nr_uninterruptible 分别表示该运行队列上可运行进程、不可中断进程的个数。累积的 nr_active 再进行指数衰减平均得到最终的平均负载) /* * The global load average is an exponentially decaying average of nr_running + * nr_uninterruptible. */ nr_active = 0; for_each_possible_cpu(cpu) nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;

    作者回复: @莫名, 是的,stress是很好的负载模拟工具! kernel/sched/loadavg.c 里有完整的load average代码

    2020-11-30
    4
    10
  • 争光 Alan
    感谢分享 我想问下 1.如果出现就D进程,我为什么好的故障方法排查在等待什么吗? 2.一直有个疑问,是不是linux的进程数不能太多?太多会有很多的调度时间造成很卡? 3.容器目前每个节点官方推荐是110个pod,openshift是250个,能问下你们这边的最佳实践不引起性能下降的前提下节点最大pod是多少个吗?

    作者回复: @争光 Alan > 1 可以 `cat /proc/<pid>/stack`, 看到进程停在内核中的哪个函数上,结合内核的代码,可以“猜一下”大概是在哪个信号量上。 > 2 进程太多会有问题的。 > 3 我们用的缺省110个pod, 不过对pod/container要做一下max pid的限制, 同时需要监控cpu/memory/disk io/ network/D process number/max pid/max fd 等等

    2020-12-02
    4
    8
  • 游离的鱼
    首先很感谢老师,然后我还是有一些些不太明白,第一个: 处于task_interruptible的进程,虽然它在等信号量和等待io上,但是我理解这个时候其实cpu是空闲的,为什么不把cpu资源让出来,等io完成或者有信号量时再把它放入可运行的队列中去等待调用呢,类似于回调函数那样的思想。第二个: 如果是我的机器长期平均负载过高,是不是一定是D状态的进程或线程引起的。 第三个: 我有四个cpu的机器,现有五个进程,有四个在cpu中运行,其中三个是处于运行状态,另一个是处于task_interruptable状态,也就是D状态,还有一个在排队,那这个时候的负载是不是就是5?如果除了刚刚的D状态的进程其他的进程都运行完了,负载是不是又变成1了。 第四个: 根据老师的定义和公式,平均负载是...的平均进程数,我感觉平均进程数是一个整数,为什么我们看到的平均负载都是带小数的。希望老师帮忙解答一下,帮我解除疑惑。万分感谢

    作者回复: > 第一个 这时候cpu仍然是空闲的,cpu也可以用来调度别的进程,只是需要竞争信号量的几个进程间相互在等待中。 > 第二个 这个就是我在文章中讲的,引起load average增高就是两个原因一个running 队列里的进程,一个是D进程。 > 第三个 如果在较长的一段时间里,都是处于这种状态,那么load average是5。只是处于D状态的进程,其实是不用cpu的,因此其他的四个进程应该都在运行。当其他的四个进程都退出了,只剩D进程,那么等待相当长的一段时间后,load average变成1. > 第四个 因为load average是过去1分钟/5分钟/15分钟的一个平均值

    2020-12-01
    2
    6
  • Jackson Wu
    老师好,一个CPU只能同时处理一个进程,为什么还能把CPU分为0.5C的单位呢,这个cpu的单位是怎么理解的呢

    作者回复: CPU是分时处理进程的。有两个进程A,B在一个CPU的机器上运行, 每一秒时间里,A可以运行0.5秒,B可以运行0.5秒,那么A拿到的CPU资源就是0.5 cpu

    2020-12-06
    3
  • 笃定
    文中的第二个实验,四个cpu的系统,运行六个进程。理论上六个进程同一时刻不可能都处于R状态吧?一个cpu同一时刻不是只能处理一个进程吗?我的理解top输出应该是四个R状态两个S状态

    作者回复: R状态的进程不是单指正在运行的进程,还指在runqueue上可以随时得到调度时间片而可以运行的进程。

    2021-03-28
    2
  • Harold
    对于 load average 的值还是有些模糊,不考虑 D 进程的情况下,1台8核的机器有 16个 running 的进程,cpu并没有占满100%的情况下,load average取的值是 16*(1 - cpu idle) 还是 16?换句话说,是不是只要 cpu idle 不是0,取的都是 cpu usage 的值。望解答。

    作者回复: > 换句话说,是不是只要 cpu idle 不是0,取的都是 cpu usage 的值. 没有D进程的情况下,是的。

    2021-01-12
    2
  • po
    有事,好几天没来留言了,我有个确认点: 1. 如果一台2个cpu的机器,跑了8个进程,每个进程使用一个cpu的10%,那么load average应该是0.8吧? 2. 平常说的物理机CPU,比如2核4线程,这个在Linux里面看是几个cpu呢?

    作者回复: @po, >1, 是的 >2, 对于处理器里的hyper-threading, 从Linux角度看到的也是1个cpu。2核4线程(hyper-threading), 看到的是4个cpu. 你可以 sys/, proc/下看到cpu信息。 /sys/devices/system/cpu/online /proc/cpuinfo

    2020-12-09
    9
    2
  • Geek4329
    感谢老师,受益匪浅! 有一点不是很懂,想请教下: “这里我们做一个kernel module,通过一个 /proc 文件系统给用户程序提供一个读取的接口,只要用户进程读取了这个接口就会进入 UNINTERRUPTIBLE。” 老师上面给的kernel module中,我的理解是只调用sleep,然后用户调用这个接口就进入D state,算是模拟DISK IO状态时获取不到资源时的状态吗?老师能不能给个参考,用户进程读是如何取了这个接口呢?

    作者回复: @Geek4329 内核模块里调用的是 msleep(), 这个函数会把进程的状态设置为TASK_UNINTERRUPTIBLE。 就用它来模拟一下。 void msleep(unsigned int msecs) { unsigned long timeout = msecs_to_jiffies(msecs) + 1; while (timeout) timeout = schedule_timeout_uninterruptible(timeout); } signed long __sched schedule_timeout_uninterruptible(signed long timeout) { __set_current_state(TASK_UNINTERRUPTIBLE); return schedule_timeout(timeout); } 用户程序读取/proc的接口的例子程序: https://github.com/chengyli/training/blob/main/cpu/load_average/uninterruptable/app-test.c

    2020-11-30
    2
    2
  • 钱米
    请问老师,我的宿主机的memory cgroup很多,处于上升趋势,未下降 ~# cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 3 30 1 cpu 2 101 1 cpuacct 2 101 1 blkio 6 99 1 memory 7 1013 1 devices 4 99 1 freezer 9 30 1 net_cls 10 30 1 perf_event 8 30 1 net_prio 10 30 1 pids 5 100 1 这个影响了api对容器的创建和启动,改如何处理呢?

    作者回复: 如果被删的memory cgroup还有cache memory, 对应的memroy cgroup 控制块不会随 /sys/fs/cgroup/memory/.../<memory_cgroup> 的删除而马上删掉。 你可以用 “echo 3 > /proc/sys/vm/drop_caches” 释放cache之后, memory cgroup num_cgroups的数值应该会下降一些。 > 这个影响了api对容器的创建和启动 这个有什么样的影响?

    2021-01-22
    1
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部