一 在容器内无法通过top命令获取真实cpu使用率
当容器云平台中一些节点出现负载过高、导致应用程序异常时,一个主要的解决方案就是找出对cpu占用过高的进程。容器云平台主要跑的都是容器进程,如何查看容器进程对cpu的真实使用率就成了一件重要的事情。
在宿主机我们可以通过top命令查看,但是在容器里,你通过top命令是无法查看到容器本身总共占用了多cpu资源的,看到的依然是宿主机的状态
我们进入容器内执行top查看:docker run -ti –name test centos:7 sh
发现容器内进程消耗0.7+0.7+0.3+0.0,而容器内的sh进程与top进程都没有消耗这么多cpu,这就验证了我们的说法:在容器内是无法通过top命令获取容器对cpu的占用率的
既然top命令做不到,那么就需要我们自己开发工作来获取容器对cpu的真实占用率,具体怎么获取?先来储备一个知识,请看下一小节
二 获取cpu的真实使用率
2.1 获取单个进程对cpu的使用率
先来储备两个非常重要的知识
-
1、关于cpu使用率
某个用户进程对cpu的利用率 = 用户进程占用的cpu时间(包括用户态us+内核态sy) / cpu经历的这段总时间
进程对cpu的利用率为100%代表使用1颗cpu
进程对cpu的利用率为200%代表使用2颗cpu
如果宿主机只有4颗cpu,那么某个进程对cpu的利用率最多400%
总结:cpu使用率反应的是cpu的利用情况 -
2、关于load average
在某段时间内平均活跃的进程数(包含系统处于可运行状态以及不可中断状态的平均进程数)
如果宿主机有4颗cpu,那么平均负载是可以超过4的
总结:负载负载反应的cpu的工作量 -
3、进程从启动那一刻开始linux操作系统就会累积该进程对cpu的资源的占用时间,没错是累加的。
举例:开机后时间在一分一秒地走,此时我们发现当前时间为18:00,某进程占用cpu的时间的累积总量为10s,然后时间来到了19:00,我们发现该进程对cpu的占用时间累积到了100s,那么在cpu经历的这一个小时内,该进程对cpu的占用时间为100s-10s
具体来说负责记录下进程对cpu资源累积占用的是linux系统中proc文件系统
top命令就是通过查看proc文件系统中每个进程对应stat文件中的2个数值来完成统计的
# 1、测试脚本
[root@test04 ~]# cat a.sh
i=0
while true;
do
let i++
done
[root@test04 ~]#
# 2、执行
[root@test04 ~]# sh a.sh &
[1] 43157
# 3、查看
[root@test04 ~]# cat /proc/43157/stat | awk '{print $14,$15}'
1314 14
cat /proc/19838/stat 的内容有50多项,包括进程pid、名字、运行状态、ppid、优先级、内存使用等。要统计cpu使用率,主要关注第14项utime与第15项目stime
-
1、utime代表进程的用户态部分在linux系统调度中获取的cpu的ticks
-
2、stime代表进程的内核态部分在linux系统调度中获取的cpu的ticks
ticks是linux系统的一个时间单位,与人们熟悉的秒、毫秒一样都是时间单位,只不过在linux中一个tick代表一次中断的周期,这个周期需要耗费的时间由中断频率HZ决定,HZ在linux系统中默认为100,可以用如下命令查看
[root@test04 ~]# getconf CLK_TCK # HZ为100代表1s内发生100次中断,
100
那想知道一个tick具体代表多长时间就是:1/100 秒,即一次中断耗费的时间是1/100秒,也就是一个tick所代表的的时间。如果utime等于150ticks,就相当于150*1/100=1.5秒,代表进程从启动那一刻到现在总共在用户态运行了1.5秒钟。
那如何统计进程对cpu的占用率呢,公式如下
进程的 CPU 使用占比 =((utime_2 – utime_1) + (stime_2 – stime_1)) / (HZ * et * 1 )
上述结果为一个小数,想要得到百分率,需要乘以100,如下
进程的 CPU 使用百分率 = ((utime_2 – utime_1) + (stime_2 – stime_1)) * 100 / (HZ * et * 1 )
et为统计的时间间隔,如果为10s,那么我们需要在开始获取一下utime_1与stime_1
然后等待10s后,再次获取,即utime_2与stime_2
那么((utime_2 – utime_1) + (stime_2 – stime_1))代表的就是10s内,该进程累积对占用的用户态与内核态的ticks总数
(HZ et 1 )中1代表1颗cpu、et代表时间间隔,HZ代表中断频率,ticks是按照固定频率发生的,在linux系统中默认HZ为100,代表1秒钟是100次,所以"(HZ et 1 )即(100 10 1)",代表10s内一个cpu总共的ticks数
综上,上面的公司我们可以简化为
进程的 CPU 使用百分率 =(某段时间内进程占内核态与用户态ticks/ 该段时间内单个 CPU 总 ticks)*100.0
最后乘以那个100代表转换为百分比
补充:一个cpu的完整工作时间,可能服务过多个进程,如下图颜色标注代表cpu服务过3个进程,红色框代表的进程可能占用的只是tick3、tick6、tick7这三个时间片,那么该段时间内,红色框进程对cpu的占用率(注意对cpu的占用率一定统计的是单颗)就是3/7
举例
我们用命令查看启动进程的cpu占用率为:7.6
[root@test04 ~]# sh a.sh &
[1] 63214
[root@test04 ~]# ps aux |head -1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
[root@test04 ~]# ps aux |grep 63214 |grep a.sh
root 63214 7.6 0.1 113552 3316 pts/0 S 12:30 1:43 sh a.sh
然后我们自己编写脚本来统计该进程对cpu的占用率
utime1=$(cat /proc/63214/stat | awk '{print $14}')
stime1=$(cat /proc/63214/stat | awk '{print $15}')
sleep 10 # 等待10s后
utime2=$(cat /proc/63214/stat | awk '{print $14}')
stime2=$(cat /proc/63214/stat | awk '{print $15}')
user_ticks=$((utime2-utime1))
sys_ticks=$((stime2-stime1))
process_total_ticks=$((user_ticks+sys_ticks))
cpu_total_ticks=$((100 * 10 * 1))
echo ${process_total_ticks} / ${cpu_total_ticks} | bc -l
输出.07600000000000000000,与我们用ps命令或者top命令看到的7.6一致
2.2 统计整个系统对cpu的使用率
top命令是如何统计出一个cpu上,所有的us进程对整颗cpu的占用率,以及sys、ni、id、wa、hi、si、st各自对本颗cpu的占用率呢?