Docker CPU Usage
背景
当一台机器上跑有多个 Docker Container 的时候,我们需要知道,哪些容器占用了多少资源。采集这些指标,来让我们可以更加好的分配资源给每个 Container。
获取容器CPU使用率
正好,这两天碰到一个需求。需要我们在监控 Host 的 CPU 时候,同时将每个容器的 CPU使用率 也要拿到。
平常我们来看容器的资源占用,通过 stat 命令就可以

这里的字段 CPU 表示了CPU的使用率。
但是这样的命令结果我们要拿到并做处理的时候并不方便。不过,据说 Docker Daemon 还有 API 接口,可以用来直接获取JSON格式的数据。
来来来,接口搞起来……
当我拿到数据的时候,我是拒绝的:
"cpu_stats" : {
"cpu_usage" : {
"percpu_usage" : [
8646879,
24472255,
36438778,
30657443
],
"usage_in_usermode" : 50000000,
"total_usage" : 100215355,
"usage_in_kernelmode" : 30000000
},
"system_cpu_usage" : 739306590000000,
"throttling_data" : {"periods":0,"throttled_periods":0,"throttled_time":0}
}
这都是些什么鬼……
其实,要理解上面的数据,要现有一些前序的知识
Linux 如何计算CPU使用率
在 Linux 中,CPU 可不是像一个有刻度的尺子一样,把百分比刻在上面,CPU使用了多少,就把刻度记录一下。
实际上,CPU使用率的计算是通过时间比率计算的。简单来说,CPU只会有两种状态: 忙(被占用)、闲(空闲)。当我们把1s的时间分成1000份,也就是以毫秒为单位来看待CPU的时候。
假设下面两种情况:
- 假设有一个进程占用了 CPU 250ms;那么整个CPU在1s的维度上来看,他的使用率是25%。
- 假设有两个进程一起使用CPU,每个都是用了 500ms;那么整个CPU使用率是 100%,每个进程占用了 50%
实际上,Linux对于CPU的使用分配和记录远比这个要复杂。比如,还要记录是系统调用的CPU占用呢 还是用户的CPU占用呢,还是等待IO的占用呢,等等。CPU时间的分配工作也是非常复杂,Linux中采用了完全公平调度器(Completely Fair Scheduler)来分配CPU。
继续深入就有点跑题了。这些东西会在今年后续的文章中陆续谈到。
那么,实际上, Linux Kernel 将 CPU 使用的信息记录在哪了呢?这个信息记录在了 /proc/stat 这个文件中。
它看起来就像下面这样:
# intr 那个字段太长,截断掉了
[root@sean ~]# cat /proc/stat
cpu 1344357 729 298522 107841813 41774 0 1754 0 0 0
cpu0 1344357 729 298522 107841813 41774 0 1754 0 0 0
intr 206534153 29 10 0 0 154 .......
ctxt 317949799
btime 1524823711
processes 677986
procs_running 3
procs_blocked 0
softirq 66031632 2 35326999 1 2928073 535817 0 32 0 0 27240708
我们关心的是第一行的意义。通过查看 man 5 proc,可以确定它的具体意义
user (1) 用户模式花费的CPU时间
nice (2) 低优先级用户态花费的CPU时间
system (3) 系统模式花费的CPU时间
idle (4) 空闲的CPU时间
iowait (since Linux 2.5.41)
(5) 等待IO的CPU时间
irq (since Linux 2.6.0-test4)
(6) 中断花费的CPU时间
softirq (since Linux 2.6.0-test4)
(7) 软中断花费的时间
steal (since Linux 2.6.11)
(8) 被虚拟环境其他操作系统占用的CPU时间
guest (since Linux 2.6.24)
(9) 在Linux内核的控制下为客户操作系统运行一个虚拟CPU花费的时间。
guest_nice (since Linux 2.6.33)
(10) 同上,低优先级的。
这些加起来,就是花费的CPU总体时间。
Container 如何记录CPU使用
这个文件中,记录了所有的进程花费的总的开销,并不能标识出某一个 Container 总共花费了多少。那如何找出 Container 的开销呢?
这个就要看 CGroup 的了。
Linux下的Container技术依赖于 CGroup(Control Group),它不仅仅追踪进程组,还会暴露 CPU、Memory、IO 使用率的指标出来。CGroup 通过伪文件系统的方式将它们记录下来。在最近几个版本的发行版中,一般会放在 /sys/fs/cgroup 中。
在这个文件夹下,可以看到多个子文件夹,代表了 cgroup 记录的各个分类
[root@test cgroup]# pwd
/sys/fs/cgroup
[root@test cgroup]# ll
total 0
dr-xr-xr-x 3 root root 0 May 10 12:59 blkio
lrwxrwxrwx 1 root root 11 Jan 29 12:07 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jan 29 12:07 cpuacct -> cpu,cpuacct
dr-xr-xr-x 3 root root 0 May 10 12:59 cpu,cpuacct
dr-xr-xr-x 3 root root 0 May 10 12:59 cpuset
dr-xr-xr-x 3 root root 0 May 10 12:59 devices
dr-xr-xr-x 3 root root 0 May 10 12:59 freezer
dr-xr-xr-x 3 root root 0 May 10 12:59 hugetlb
dr-xr-xr-x 3 root root 0 May 10 12:59 memory
dr-xr-xr-x 3 root root 0 May 10 12:59 net_cls
dr-xr-xr-x 3 root root 0 May 10 12:59 perf_event
dr-xr-xr-x 3 root root 0 May 10 12:59 pids
dr-xr-xr-x 5 root root 0 May 10 12:59 systemd
对于 Docker 来说,在每一个分类下,都会有一个 docker 的文件夹,来记录docker相关的信息。而docker container 的信息,则记录在 更下一层的目录中,以 container 的 全ID 为目录名。以记录container CPU相关的信息为例,目录应该在 /sys/fs/cgroup/cpu/docker/<container-full-id>。
对于 CPU 来说,Linux 使用了 The CPU Accounting (cpuacct) 子系统。它会定期自动汇报有关 CGroup中 任务使用 CPU 资源的使用情况。
cpuacct 有三种汇报记录:
cpuacct.statGroup中 CPU 总共的使用时间(纳秒为单位),包含所有类型的CPU消耗cpuacct.usageGroup中 用户模式 和 系统模式 各自使用的 CPU时间。这个汇报的单位是 1/100 秒,在 Linux 中也叫"user jiffies"。文件中有两个字段- user 用户使用的 CPU时间
- system 系统使用的 CPU 时间
cpuacct.usage_percpu每个 CPU 的使用时间
total 0
-rw-r--r-- 1 root root 0 May 9 18:22 cgroup.procs
-r--r--r-- 1 root root 0 May 10 13:07 cpuacct.stat
-rw-r--r-- 1 root root 0 May 10 13:07 cpuacct.usage
这就是,到现在为止,我们需要的所有前置知识啦。下面我们回到主题。
/container/<cid>/stats API 的CPU数据如何来的?
这些数据就是我们上面两个小节所讲的地方拿来的。
"cpu_stats" : {
"cpu_usage" : {
"percpu_usage" : [
8646879,
24472255,
36438778,
30657443
],
"usage_in_usermode" : 50000000,
"total_usage" : 100215355,
"usage_in_kernelmode" : 30000000
},
"system_cpu_usage" : 739306590000000,
"throttling_data" : {"periods":0,"throttled_periods":0,"throttled_time":0}
}
cpu_usage 中的所有的值 是从 cpuacct.usage、cpuacct.usage_percpu、cpuacct.stat 获取。
system_cpu_usage 从 /proc/stat 中获取。
⚠️ 这里需要注意的是,这三个文件中,cpuacct.stat 使用的单位和 其他两个是不一样的,在获取数据的代码中,要将以 USER_HZ 单位的值转为 以纳秒为单位的值。
来看看代码
有了数据,怎么计算 Container CPU 使用率
我把它贴在下面,分析一下:
func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
var (
cpuPercent = 0.0
// calculate the change for the cpu usage of the container in between readings
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
// calculate the change for the entire system between readings
systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
}
return cpuPercent
}
有同学说,有了系统总时间,有了Container总时间,做一个简单的除法运算就可以完成比例的运算过程:
Container CPU使用率 = container CPU使用总时间 / 系统CPU的总时间 * CPU核数
注意,注意!这个是有问题的。
注意,注意!这个是有问题的。
注意,注意!这个是有问题的。
前面讲过了,这个数值是 使用CPU的时间,如果计算的时候抛开了时间的概念,那么肯定是不对的。在刚才那个算式中,有一个假设的前提:Container启动的时间 和 系统的启动时间 是一样的。这明显是不对的。
所以,参见上面的代码。Docker 在计算 Container 的 CPU使用率 的时候,会取两次数值,通过两次数值的差值再计算使用率。
其他 metrics
我们的文章主要介绍了如何获取CPU使用率。但是,其他的指标也是同样的方法,比如内存使用,IO使用。
源码在我贴出的代码片段附近就可以看到,有兴趣的同学可以继续深入研究下。
结尾
作者和出处(reposkeeper) 授权分享 By CC BY-SA 4.0
关注微信公众号,获取新文章的推送!

Docker CPU Usage的更多相关文章
- Docker CPU 资源限制——CPU分片功能测试
之前的一篇随笔——Docker CPU 资源限制 中介绍了针对COU的某个或某几个核的控制,今天介绍下CPU分片功能,即CPU占比. 测试步骤 1.下载CPU测试image.agileek/cpuse ...
- CPU利用率和CPU负荷(CPU usage vs CPU load)
对于CPU的性能监测,通常用top指令能显示出两个指标:cpu 利用率和cpu负荷. 其中%Cpu相关的内容: us表示用户进程cpu利用率,sy表示系统内核进程cpu利用率,ni表示运行正常进程消耗 ...
- Unity Profiler CPU Usage(CPU使用情况)
在Profiler界面点击左侧CPU Usage,Profiler界面下方Hierarchy窗口会列出各个函数对当前CPU的耗时,从大到小排序. 然后分析,各个函数的耗时是否异常,分析有没有可以优化的 ...
- How to Limit NodeRunner.exe High Memory, CPU Usage
roblem: NodeRunner.exe is consuming a lot of memory and CPU resulted in performance issues on ShareP ...
- CPU Usage (C#) 测试
注意:算法仅供参考. cpuusage.cs using System; using System.Collections.Generic; using System.Diagnostics; usi ...
- C++第四十二篇 -- CPU Usage
前言 目的:读取并控制CPU占用率 近期在做CPU Usage方面的事情,让CPU以一种高占用率的状态运行一定的时间,需要读取CPU各个核的占用率,网上关于这方面的资料好少,FQ也只找到了一个WMI的 ...
- Docker CPU 资源限制——CPU固定核功能测试
Docker使用Linux cgroup来实现资源的限制,对于CPU的限制有两种方法: 1.cpuset CPU Set限定容器使用某个固定的CPU核.使用默认的libcontainer引擎时,可以通 ...
- 关于sys CPU usage 100%问题的分析
最近一个客户抱怨他的核心EBS数据库出现性能问题.这是一个10.2.0.3的数据库,运行在Red Hat Enterprise Linux Server release 5.5 (Linux x86- ...
- 【DPDK】【CPU usage】DPDK应用如何计算当前系统的压力
[前言] 使用DPDK开发的朋友应该都了解使用dpdk的fwd线程的工作模式是polling模式,即100%轮询的方式去加速网络IO,这样我们在操作系统层面上来观察目标processer会发现usag ...
随机推荐
- python面向对象编程(2)—— 实例属性,类属性,类方法,静态方法
1 实例属性和类属性 类和实例都是名字空间,类是类属性的名字空间,实例则是实例属性的名字空间. 类属性可通过类或实例来访问.只有通过类名访问时,才能修改类属性的值. 例外的一种情况是,当类属性是一个 ...
- recycle bin tip
if you have a question about recycle bin that can look the follow link; http://www.dba-oracle.com/t_ ...
- August 25th 2017 Week 34th Friday
Stop to have a rest, do not forget others still in the running. 停下来休息的时候,不要忘记别人还在奔跑. You don't need ...
- php给$_POST赋值会导致值为空
在调试一个程序的时候发现很奇怪的现象,post传过来的值再某些地方为空,先看下面的代码 <?php if($_POST['submit'] == 'Add'){ if($_POST['type' ...
- pat 5—1 求该日是该年的第几天
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 前面还是欠了一堆,慢慢补吧. 看了别人的博客才知道前面有一次圆面积的题,我上课是在干啥......... 打是打出来了,但是还是有几个蒙蔽的地方: ...
- python,dict的setdefault方法
@dict的setdefault方法 先看看文档中的解释 setdefault(...) D.setdefault(k[,d]) -> D.get(k,d), also set D[k]= ...
- 【PHP】 mysqli_autocommit() 函数
//获取每一篇文章的内容 function getPost($f_parent_id, $f_title, $f_username, $f_board_id,$f_post_time, $f_ip,$ ...
- Windows下Python3.6安装PIL
PIL是Python平台事实上的图像处理标准库,需要用到图片的需要导入该模块 一 安装pip https://pip.pypa.io/en/stable/installing/#id8 python ...
- Redis简单集群配置
参考链接为:http://blog.csdn.net/u014230881/article/details/71123494 比较系统学习和熟练使用Redis命令可参考该教程:http://www.r ...
- 算法——(5)B/B+/红黑树
1. B树——lgdN B树是平衡多路查找树,主要用于文件系统的索引. 1)定义: 对于一个度数为d的B树, 每个结点最多有d个孩子 如果根结点不是叶子结点,那它至少有两个孩子 每个非叶子结点(非根结 ...
