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

本文仅作为学习记录,非商业用途,侵删,如需转载需作者同意。

CPU Cgroup 无法控制 Load Average 的平均负载。而没有这个限制就会影响系统资源的合理调度,很可能导致我们的系统变得很慢。

今天说下为什么加了CPU Cgroup的配置后,即使保证了容器的CPU资源,容器中的进程还是会运行的很慢。

一、问题再现

容器里的 CPU甚至宿主机上的CPU 使用率都很低,但是机器的Load Average 却很高,容器里的进程也很慢。

在这里插入图片描述
如上面的图片,CPU使用率很低,id值空闲很高。但是Load Average 的值高达9.09,就意味着使用了9个CPU。

这样就很矛盾了,哪个值是正确的呢?就需要解决两大问题

  • Load Average 到底是什么?CPU Usage 和 Load Average有什么差别?
  • 如果Load Average值升高,应用性能下降了,这背后是什么原因

二、什么是Load Average

Load Average 三个数值代表过去 1分钟,5分钟,15分钟在这个节点上的Load Average,它是一种CPU 资源需求的度量。

举例说明:
对于一个单个CPU系统,如果在1分钟的时间里,处理器上始终有一个进程在运行,同时操作系统的进程可运行队列中始终都有9个进程在等待获取CPU资源。 对于这1分钟的时间里,系统的 load average 就是 1+9=10

Load Average:单位时间内正在运行的进程 + 可运行队列的进程

三点理解:

  • Load Average 都是Linux 进程调度器中可运行队列(Running Queue)里的一段时间的平均进程数目
  • 计算机上的CPU还有空闲的情况下,CPU Usage可以直接反映到 load average 。 什么是CPU 还有空闲呢?具体来说就是可运行队列中的进程数目小于CPU个数。 这种情况下,单位时间进程 CPU Usage 相加的平均值应该就是 load average的值。
  • 计算机上的CPU 满负载的时候,同时还有更多的进程在排队需要CPU资源,这时 load average 就不能和 CPU Usage 等同了。

说明:
对于单个CPU的系统,CPU Usage 最大只有100%,也就是1个CPU,而load average 的值可以远远大于1,因为 load average 看的是操作系统中可运行进程队列中进程的个数。

下面的内容直接复制过来了,是测试过程的内容

准备一个可以消耗任意 CPU Usage 的测试程序地址:

https://github.com/chengyli/training/tree/master/cpu/cgroup_cpu/threads-cpu

比如下面的设置,参数是 2,就是说这个进程会创建出两个线程,并且每个线程都跑满 100% 的 CPU,2 个线程就是 2 * 100% = 200% 的 CPU Usage,也就是消耗了整整两个 CPU 的资源。

# ./threads-cpu 2

准备好了这个 CPU Usage 的模拟程序,我们就可以用它来查看 CPU Usage 和 Load Average 之间的关系了。

接下来我们一起跑两个例子,第一个例子是执行 2 个满负载的线程,第二个例子执行 6 个满负载的线程,同样都是在一台 4 个 CPU 的节点上。

先来看第一个例子,我们在一台 4 个 CPU 的计算机节点上运行刚才这个模拟程序,还是设置参数为 2,也就是使用 2 个 CPU Usage。在这个程序运行了几分钟之后,我们运行 top 来查看一下 CPU Usage 和 Load Average。

我们可以看到两个 threads-cpu 各自都占了将近 100% 的 CPU,两个就是 200%,2 个 CPU,对于 4 个 CPU 的计算机来说,CPU Usage 占了 50%,空闲了一半,这个我们也可以从 idle (id):49.9% 得到印证。

这时候,Load Average 里第一项(也就是前 1 分钟的数值)为 1.98,近似于 2。这个值和我们一直运行的 200%CPU Usage 相对应,也验证了我们之前归纳的第二点——CPU Usage 可以反映到 Load Average 上。

因为运行的时间不够,前 5 分钟,前 15 分钟的 Load Average 还没有到 2,而且后面我们的例子程序一般都只会运行几分钟,所以这里我们只看前 1 分钟的 Load Average 值就行。

另外,Linux 内核中不使用浮点计算,这导致 Load Average 里的 1 分钟,5 分钟,15 分钟的时间值并不精确,但这不影响我们查看 Load Average 的数值,所以先不用管这个时间的准确性。

在这里插入图片描述

那我们再来跑第二个例子,同样在这个 4 个 CPU 的计算机节点上,如果我们执行 CPU Usage 模拟程序 threads-cpu,设置参数为 6,让这个进程建出 6 个线程,这样每个线程都会尽量去抢占 CPU,但是计算机总共只有 4 个 CPU,所以这 6 个线程的 CPU Usage 加起来只是 400%。

显然这时候 4 个 CPU 都被占满了,我们可以看到整个节点的 idle(id)也已经是 0.0% 了。

但这个时候,我们看看前 1 分钟的 Load Average,数值不是 4 而是 5.93 接近 6,我们正好模拟了 6 个高 CPU 需求的线程。这也告诉我们,Load Average 表示的是一段时间里运行队列中需要被调度的进程 / 线程平均数目。

在这里插入图片描述

为啥还需要考虑可运行队列中的进程数目呢

因为那时开发者Matthias 有这么一个发现,比如把快速的磁盘换成了慢速的磁盘,运行同样的负载,系统的性能是下降的,但是 Load Average 是没有体现的。

因为之前的 Load Average 只考虑运行态的进程数目,而没有考虑等待I/O 的进程。

处于 I/O 资源等待的进程都是处于 TASK_UNINTERRUPTIBLE 状态。(我猜,不可中断的是指内核态中运行,因为用户态中运行肯定就可以被中断了,相对来说)

于是,作者就给内核打了一个补丁,把处于 TASK_UNINTERRUPTIBLE 状态的进程数目也计入了 load average。
这种状态是Linux进程状态的一种,是进程为了等待某个系统资源而进入了睡眠状态,并且这种睡眠的状态是不能被信号打断的。
类似于:钱都付了,师傅正在炒菜,你说这个菜不要了。这样不太好,不能退了。

Running Queue :可运行队列
Sleeping Queue:休眠队列,这个里面分为可中断和不可中断

不可中断(TASK_UNINTERRUPTIBLE),显示为D state

在这里插入图片描述

总结下,平均负载统计了这两种情况的进程:

  • 1、Linux调度器中可运行队列(Running Queue)一段时间(1分钟,5分钟,15分钟)的进程平均数
  • 2、Linux进程调度器中休眠队列(sleeping Queue)里的一段时间的TASK_UNINTERRUPTIBLE 状态下的进程平均数

最后的公式就是:
Load Average = 可运行队列进程数平均数 + 休眠队列中不可打断的进程平均数

打个比方:
每个CPU 就是一条道路,每个进程都是一辆车,怎么统计道路的负载呢? 就是看单位时间通过的车辆,一条道路上车越多,这条道路的负载就越高。

Linux 计算系统负载的时候,还额外做了补丁,把 TASK_UNINTERRUPTIBLE 状态的进程也考虑进去了。
就像道路中要把红绿灯情况也考虑进去,一旦有个红灯,汽车就要停下来排队,那么即使道路很空,但是红灯多了,汽车也要排队等待,也开不快。

三、现象解释:为什么 Load Average 会升高

为什么对容器已经用CPU Cgroup 限制了它的CPU Usage,容器里的进程还是可以造成系统很高的Load Average。

Linux下的Load Average不仅仅计算了CPU Usage的部分,它还计算了系统中TASK_UNINTERRUPTIBLE状态的进程的数目

如果Load Average 值升高了,应用的性能下降了,问题就是出在TASK_UNINTERRUPTIBLE 状态进程上了。

这个使用 ps aux | grep “D” 就可以看到容器中有多少TASK_UNINTERRUPTIBLE 状态的进程。

在Linux中内核中有数百处调用点,它们会把进程设置为D 状态,主要集中在 disk I/O 的访问和信号量(Semaphore)锁的访问上,因此D状态的进程在Linux里很常见。

无论是对disk I/O 的访问还是对信号量的访问,都是对Linux系统里的资源的一种竞争。

当进程处于D状态时,就说明进程还没获得资源,这会在应用程序的最终性能上体现出来,也就说用户会发觉应用的性能下降了。

目前D 状态进程引起的容器中性能下降的问题,Cgroup还不能解决,这也就是为什么我们做了 Cgroups的配置,即使保障了容器的CPU资源,容器中的进程还是运行很慢的根本原因。

为什么CPU Cgroups 不能解决这个问题呢?
因为Cgroups 更多的是以进程为单位进行隔离,而D 状态进程是内核中系统全局资源引入的,所以Cgroups 影响不了它。

我们可以做的是,在生产环境中监控容器的宿主机节点里 D 状态的进程数量,然后对 D 状态进程数目异常的节点进行分析,比如磁盘硬件出现问题引起 D状态进程数目增加,这时就需要更换硬盘。

四、重点总结

Load Average 计算的是进程调度器中可运行队列(Running Queue)里的一段时间(1 分钟,5 分钟,15 分钟)的平均进程数目,而 Linux 在这个基础上,又加上了进程调度器中休眠队列(Sleeping Queue)里的一段时间的 不可中断TASK_UNINTERRUPTIBLE 状态的平均进程数目。

在这里插入图片描述

因为 TASK_UNINTERRUPTIBLE 状态的进程同样也会竞争系统资源,所以它会影响到应用程序的性能,我们可以在容器宿主机的节点对 D 状态进程监控,定向分析解决。

对 D 状态进程的监控也很重要,因为这是通用系统性能监控的方法。

%iowait 表示在一个采样周期内有百分之几的时间属于以下情况:CPU空闲、并且有仍未完成的I/O请求。 就是由于IO导致无法充分利用CPU的时间。

五、评论

一、

问题:引入为 TASK_UNINTERRUPTIBLE 状态的进程的案例,top 输出中为什么wa使用率这一项没有增长?

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

二、

stress 压测工具:stress -c 1 -t 600

三、

问题:
一个: 处于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分钟的一个平均值。

四、

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

回答:
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 等等

五、

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

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

六、

作者回复: 如果被删的memory cgroup还有cache memory, 对应的memroy cgroup 控制块不会随 /sys/fs/cgroup/memory/…/<memory_cgroup> 的删除而马上删掉。

你可以用 “echo 3 > /proc/sys/vm/drop_caches” 释放cache之后, memory cgroup num_cgroups的数值应该会下降一些。

七、

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


问题:文首提到的Cgroup无法限制LoadAverage,从而可能导致整个系统性能下降。指的是处于D状态进程的性能下降,而D状态进程对同一资源的竞争越来越多,整体表现出来就是系统性能下降。这样理解对吗?

回答:是的

问题:老师好,一个CPU只能同时处理一个进程,为什么还能把CPU分为0.5C的单位呢,这个cpu的单位是怎么理解的呢

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


问题:
假设系统4CPU,平均负载很高为8,每个任务使用100% CPU可发挥最高性能
1. 如果都是CPU密集型负载,那么CPU使用率不超过50%,应用性能肯定下降
2. 如果全部是IO密集型负载,那么都在竞争IO资源,应用性能肯定下降
3. 假设有小于4个的CPU密集型负载,其他都是IO密集型负载,那么CPU密集型负载的性能应该不受影响。

回答:
对于1,2,3点,我的理解和你一样。

不过还是要说一下,I/O高的应用不一定是D进程,而只有D状态才是处于等待资源,才会引起load average增高。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值