user CPU:CPU用户进程的时间百分比
system CPU:CPU执行系统调用的时间百分比
CPU util:总的CPU使用率
throttling (count):容器的CPU被限制的次数
throttling (time):容器的CPU使用率被限制的总时间
采集方式 $ cat /sys/fs/cgroup/cpuacct/docker/$CONTAINER_ID/cpuacct.stat> user 2441 # docker开启后运行用户进程的时间> system 985 # docker开启后运行系统调用的时间 在x86系统中,上面的时间是按10毫秒增加,所以上面的CPU在用户进程上消耗24.41秒,在系统调用上消耗9.85秒。 $ cat /sys/fs/cgroup/cpuacct/docker/$CONTAINER_ID/cpuacct.usage_percpu> 44154016900 # docker开启后单使用CPU的纳秒(44.15s) 上面是单个CPU使用的时间,如果容器使用的是多核的CPU,那么下面可以获取所有CPU的总的时间: $ cat /sys/fs/cgroup/cpuacct/docker/$CONTAINER_ID/cpuacct.usage> 44154016900 # 所有CPU使用的总纳秒(44.15s) 对于Throttled,可以在cpu.stat中获取: $ cat /sys/fs/cgroup/cpu/docker/$CONTAINER_ID/cpu.stat> nr_periods 565 # 已经过去的执行过的period数> nr_throttled 559 # CPU被限制的次数> throttled_time 11219582971 # CPU被限制的总时间,纳秒为单位 (11.22 seconds) 指标解读 我们知道在Docker中对CPU的限制方式有几种,可以通过--cpu-shares,--cpu-period和--cpu-quota,--cpuset-cpus来配置,具体细节这里不赘述。现在使用最多的方式是--cpu-period和--cpu-quota结合的方式,这时候CPU使用率的上限由两者共同决定,比如说A容器配置的--cpu-period=100000 --cpu-quota=50000,那么A容器就可以最多使用50%个CPU资源,如果配置的--cpu-quota=200000,那就可以使用200%个CPU资源。所有对采集到的CPU used的绝对值没有意义,还需要参考上限。还是这个例子--cpu-period=100000 --cpu-quota=50000,如果容器试图在0.1秒内使用超过0.05秒,则throttled就会触发,所有throttled的count和time是衡量CPU是否达到瓶颈的最直观指标。 另外,不像传统的host,Docker不需要采集CPU的nice,idle,iowait和irq时间。 内存 相关性能指标Memory:容器的内存使用
RSS:进程除了缓存之外的内存消耗(包括栈和堆内存,等等)
Cache memory:内存中的磁盘数据缓存
Swap:swap使用总量
采集方式 下面的命令会打印出一大堆的关于内存的信息,可能比你需要的多的多: $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.stat cache rss mapped_file writeback swap pgpgin pgpgout pgfault pgmajfault inactive_anon active_anon inactive_file active_file unevictable hierarchical_memory_limit hierarchical_memsw_limit total_cache total_rss total_rss_huge total_mapped_file total_writeback total_swap total_pgpgin total_pgpgout total_pgfault total_pgmajfault total_inactive_anon total_active_anon total_inactive_file total_active_file total_unevictable 虽然上面得到的很多,但是通常我们更关心的核心指标在/sys/fs/cgroup/memory/docker/$CONTAINER_ID/的其他目录中: # 总的内存使用: cached + rss $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.usage_in_bytes# 总的内存使用 + swap的使用$ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.memsw.usage_in_bytes# 内存使用达到限制的次数$ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.failcnt# 容器被限制使用的内存值 $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.limit_in_bytes 指标解读 使用的内存可以分解为: RSS:RSS本身可以进一步分解为活动和非活动内存(active_anon和inactive_anon)。必要时,非活动的RSS内存被交换到磁盘。 Cache:反映缓存在当前内存中的磁盘上的数据。缓存可以进一步分解为活动和非活动内存(active_file,inactive_file)。 当系统需要内存时,可以首先回收非活动内存。 虽然cache这部分是可以多个容器共享的,但是在Docker中CGroup判断memory.failcnt是否加一,是根据总的内存(RSS+Cache)是否达到memory.limit来决定。所以如果监控到容器的内存使用量一直上升,需要分清是RSS还是Cache导致的增加,如果是RSS的需要看下应用是否有内存泄露,如果是Cache部分,需要看最后是否能释放。 mem failcnt发生不一定会导致容器OOM,因为有些内存被Cache用到了,OS清理掉一些Cache就没问题了。作为开发者,需要调查下, 给应用划分的Docker内存上限是否合理。因为Cache被清掉就意味着后续有文件读取操作的时候,需要将数据块从磁盘page in到Cache里,如果应用的服务性能比较依赖磁盘上的数据读取性能,就需要关注下。 另外,在调查性能或稳定性问题时可能有价值的其他指标包括page faults,可以表示分段错误或从磁盘而不是内存中获取数据(分别为pgfault和pgmajfault)。 I/O 相关性能指标I/O serviced:I/O操作的次数
I/O service bytes:读写的byte数
采集方式 在目录/sys/fs/cgroup/blkio/docker/$CONTAINER_ID/下有IO相关的指标文件,由于系统的差异,下面大部分文件里面的值都是0,在这种情况下,通常还有两个文件可以工作:blkio.throttle.io_service_bytes和blkio.throttle.io_serviced,它们分别记录了总I/O字节和操作。注意别被文件名误导,这里并不是IO throttle的指标。 这些文件里前两个数字是主要:次要设备ID,例如blkio.throttle.io_service_bytes的输出示例: 253:0 Read 13750272253:0 Write 180224253:0 Sync 180224253:0 Async 13750272253:0 Total 13930496 指标解读 块I/O是共享的,所以容器的I/O是没有作限制的,也就没有类似于throttle这样的指标,那么除了上面提到的容器特定的I/O指标之外,跟踪主机的队列和服务时间也是不错的选择。如果容器使用的块设备上的队列长度或服务时间不断增加,容器的I/O将受到影响。 网络 相关性能指标Bytes:网络流量(包括接收和发送)
Packets:网络包的个数(包括接收和发送)
Error(receive):接收错误的数据包个数
Error(transmit):传输错误的数据包个数
Dropped:丢弃的包个数(包括接收和发送)
采集方式 与上面不同的是,网络相关的指标不在CGroup的文件夹下,而是采用平常进程的网络指标采集方式(毕竟Docker也是一个进程),在/proc/下获取: $ CONTAINER_PID=`docker inspect -f '{{ .State.Pid }}' $CONTAINER_ID`$ cat /proc/$CONTAINER_PID/net/dev | Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed eth0: 1296 16 0 0 0 0 0 0 816 10 0 0 0 0 0 0 lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 指标解读 同样,网络没有throttle这样的值,衡量时,需要结合网卡的兆数来看。 连接数 相关性能指标established:建立的连接
close:close状态的连接
close_wait:close_wait状态的连接
time_wait:time_wait状态的连接
……
采集方式 和上面的网络的采集差不多,我们也是通过Docker的pid的方式从/proc/下面去取,具体的文件为/proc/net/tcp和/proc/net/tcp6(如果没有用tcp6可以忽略之)。 $ cat net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 0100007F:274C 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 10547 1 ffff880426cb0000 100 0 0 10 0 1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 10616 1 ffff880426cb0780 100 0 0 10 0 2: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 11239 1 ffff880426cb1680 100 0 0 10 0 3: 00000000:2742 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 19286 1 ffff880427900780 100 0 0 10 0 4: B42A020A:2742 D014020A:C683 06 00000000:00000000 03:00000CF2 00000000 0 0 0 3 ffff8804216c7d00 5: B42A020A:2742 D014020A:879D 06 00000000:00000000 03:00001259 00000000 0 0 0 3 ffff8804216c7e00 6: B42A020A:638C 3602030A:0885 01 00000000:00000000 00:00000000 00000000 0 0 64399466 1 ffff8804256fe180 20 4 30 10 -1 7: B42A020A:2742 D014020A:B04A 06 00000000:00000000 03:000016ED 00000000 0 0 0 3 ffff8804216c6500 8: B42A020A:2742 D014020A:CC0F 06 00000000:00000000 03:00000D61 00000000 0 0 0 3 ffff8804216c6800 9: B42A020A:688D 4C02030A:276A 01 00000000:00000000 00:00000000 00000000 0 0 64348606 1 ffff880426cb5280 20 4 30 10 12 10: B42A020A:2742 D014020A:AE80 06 00000000:00000000 03:00001688 00000000 0 0 0 3 ffff8804216c7000 11: B42A020A:DC39 3502030A:0885 01 00000000:00000000 00:00000000 00000000 0 0 63592428 2 ffff8804256fb480 20 4 30 10 -1 12: B42A020A:851F 4B02030A:276A 08 00000000:00000001 00:00000000 00000000 0 0 12895659 1 ffff8804220b4b00 20 4 28 10 7 其中关注第四列,st就是连接的状态,用下面的数字来表示,具体到和连接状态的映射关系: "01": "established", "02": "syn_sent", "03": "syn_recv", "04": "fin_wait1", "05": "fin_wait2", "06": "time_wait", "07": "close", "08": "close_wait", "09": "last_ack", "0A": "listen", "0B": "closing", "0C": "unknown", 对照映射关系将他们加起来就可以得到对应状态的连接数了。 磁盘 相关性能指标used:磁盘使用量
used percent:磁盘使用率
采集方式 对于磁盘的采集,我们没有找到一个简便的方法,现在的做法是侵入到容器内部去采集,类似这样的命令: `docker exec -i $CONTAINER_PID "df"|grep -v "tmpfs"` 我们来看看直接df之后的结果: Filesystem 1K-blocks Used Available Use% Mounted on/dev/mapper/docker-253:0-1049953-53ec5aa5f4a669b3a26b19cc2675f5537ba59014419e97324f703cb050152cc6 10475520 44496 10431024 0% /tmpfs 98894428 0 98894428 0% /devtmpfs 98894428 0 98894428 0% /sys/fs/cgroup/dev/mapper/VolGroup01-lv_root 279403540 38459756 226727800 15% //dev/mapper/VolGroup00-lv_root 279403540 38459756 226727800 17% /tmpfs 98894428 2384 98892044 782 99% //dev/mapper/VolGroup00-lv_root 279403540 38459756 226727800 15% //dev/mapper/VolGroup00-lv_root 279403540 38459756 226727800 15% /etc/hostname/dev/mapper/VolGroup00-lv_root 279403540 38459756 226727800 15% /etc/hostsshm 65536 0 65536 0% /dev/shmtmpfs 98894428 0 98894428 0% /proc/kcoretmpfs 98894428 0 98894428 0% /proc/timer_statstmpfs 98894428 0 98894428 0% /proc/sched_debug 我们去掉tmpts之后,对剩下的解析,Mounted on在根目录下(/)的device mapper就是我们要的那一行,然后就可以分别得到磁盘的used,available和used percent值了。 指标解读 其实在正确的Docker使用中是不会需要采集磁盘容量的,因为我们对文件的写入应该持久化在宿主机的磁盘上。而且这种采集对资源的消耗很大,如果有需要也要酌情设置采集频率。 指标解读 对于这些不同状态的连接,可以按需去采集。cAdvisor:Google开发的容器监控指标采集,还支持聚合和一些数据处理;
Telegraf:Influxdata开发的收集Agent,这是一个通用的采集Agent,当然也支持Docker,另外该公司还提供了一整套监控方案叫做TICK,也欢迎大家去踩坑;
Prometheus:现在最火的Cloud方面的监控,而且是一整套的解决方案,包括告警、存储等等;
除此之外还有一些收费的方案,例如Datadog、Sensu、Scout等等也提供了另外的选择。