CPU利用率是系统性能监控的重要指标。CPU利用率是开发人员系统性能优化的重要参考指标。当CPU总体利用率过高时,开发过程中需要根据具体情况进行考虑,在从程序层面优化还是从部署层面优化。程序层面通过降低不必要的计算以节省CPU,系统层面通过采用分布式架构,使更多的CPU参与到计算中。当CPU总体利用率偏低时,在数据中心的角度,可以理解为,投入产生比不合适。即系统的设备没有完全利用起来,可以考虑减少服务设备的方式省系统成本。虚拟化和容器技术是解决此类情况的较好的方案,使多个应用共用系统,降低CPU的利用率。当然,上述技术在实施时,需要考虑的问题不仅仅单纯这一个角度。比如,还进一步需要考虑峰值的情况。特别是系统的吞吐比较大时,波峰需要单独处理。有时还需要考虑多应用间的相互影响,多应用的波峰会不会在同时时刻存在。多应用能否可根据应用情况在多个节点间均衡等等一系列的问题。总之其出发点只有一个,在确保应用能够正常运营的情况下,尽可能的减少使用资源,提高系统的使用效率。
从人的视角,我们更关注利用率。从计算机的视角,它只能够统计CPU的使用时间。这两者的转化通过CPU利用率的监控程序来实现。比如iostat
、top
等。从计算的角度,CPU利用率体现的时CPU使用时间和CPU运行时间的比值。为了监控和分析方便,我们可能需要关注CPU的即时利用率和CPU在某时间内在的平均利用率。前者反应的了CPU的负载波动情况,后者反映CPU资源是否得到了具体的利用。而在实现的数据统计过程中,CPU在某一时刻,其利用情况无非在使用或者不在使用,即100%或者0%。对我们无太多的参考价值。因而,CPU的即时利用率反应非直正的即时,而是在某一统计时间内的均值。通过均值连成线,系统就能呈现出其CPU的动态即时负载情况。
设前一次CPU运行的总时间长期为jiffies_pr,当前CPU运行总时间为jiffies_cur,前一次监控用户进行程占用的时间为jiffies_user_pr,当前用户进程占用时间为jiffies_user_cur,则
percentage=jiffies_user_cur−jiffies_user_prjiffies_cur−jiffies_pr
为更加详细的分析CPU的负载情况,Linux操作系统对CPU的使用为成8进行处理。如下表所示:
类别 | 说明 |
---|---|
CPUTIME_USER | 普通用户进程所占用时间 |
CPUTIME_NICE | 高优先级用户进程所占用时间 |
CPUTIME_SYSTEM | 内核系统所占用时间 |
CPUTIME_SOFTIRQ | 软中断所占用时间 |
CPUTIME_IDLE | CPU空闲时间 |
CPUTIME_IOWAIT | IO等待时间 |
CPUTIME_STEAL | Hypervisor运行占用时间 |
CPUTIME_GUEST | 虚拟机运行占用时间 |
CPUTIME_GUEST_NICE | 高优化级虚拟级进程所占用时间 |
而CPU总体运行时间为:
totaljiffies=cpu_user+cpu_nice+cpu_sys+cpu_idle+cpu_iowait+cpu_hardirq+cpu_steal+cpusoftirq
linux内核通过/proc/stat
输出CPU的统计信息。统计信息体现了从系统启动到当前时间的系统各类负载的计数情况。iostat
之类的统计程序首先从这里获取统计信息,进行百分比的换算,然后展现出来。
[root@localhost sysstat]# cat /proc/stat
cpu 19528 172 55646 34700894 153440 0 10024 0 0 0
cpu0 19528 172 55646 34700894 153440 0 10024 0 0 0
intr 13531733 129 10 0 0 0 0 0 0 0 0 0 0 155 0 0 340101 4336110 0 0 195598 0 651148 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 15768816
btime 1508742029
processes 53214
procs_running 2
procs_blocked 0
softirq 10080346 1 3478603 70015 4532140 745643 0 50129 0 0 1203815
stat信息体现的是CPU自启动到当前时刻的各类使用系统信息的计数。
– cpu及cpu{0,cpu_nr}:记录CPU在各类作业里面使用的时间。从左到右依次是user、nice、system、idle、iowait、irq、softirq、steal、guest、guest_nice
– ctx:上下文切换时间
– btime:启动时间,以秒为单位
– processes:进程数,当用fork或者clone函数创建进程时,此计数将累加
– procs_running:正在执行的进程数
– procs_blocked:由于等待IO而被阻塞的进程数
– softirq:软件中断数量。第一个数值表示总的软中断数量。后续的数值表示每个软中断的数量
ctx、btime、proceses及以后的信息比较容易理解。系统在执行到相应的操作,对系统计数并保存到内存即可以。
cpu状态信息的统计稍微复杂。
系统启动时,每个CPU均创建一个tick_device(时钟设备)用于周期性的执行系统的监控。此设备以HZ(默认配置为100)为单位执行周期性的检查函数。这个检查最终调用account_process_tick
对CPU的运行时间进行分类计数。其计数粒度为时间钟设备执行的周期( period=1s/HZ=10ms )。系统首先计算在监控周期内虚拟机所占用的时间,如果虚拟机占用的时间超过一个周期的时间话,说明CPU被虚拟机占用,这个周期的时间长度会累加到steal
中。否则的话,进一步分配period - steal
的时间长度。如果当前运行的是用户空间类型则累加到user
上。如果是系统内核进程,进一步判断是否是中断例程,如果是的话累加到相应的中断计数上,否则,认为是累加到system
值。
系统即不是用户线程在执行也不是内核线程在执行,那么,CPU当前是空闲的。需要进一步分析空闲的原因是没事干,还是有事干不了(等待IO)。如果这个时候有IO在等待执行,就认为CPU是有事干不了,等待IO的进行,将此周期增加到iowait
上。否则,CPU确实是闲着。
由上述的过程,设想,在统计周期内,系统从用户空间切的到内核空间,系统这一个周期实际上是计算在system
这个值上了。我们可以得出一个结论:CPU的时间统计是有一定的误差的。每次统计的误差均会小于统计周期。这个误差不影响我们在文档开始说的,CPU统计的指导意义,即不影响我们判断CPU当前是空闲还是繁忙,哪类操作占用的CPU比较多。
CPU统计的另外一个误差还体现的IOwait上。统计例程将当前有IO等待且CPU没有执行的情况定义为IOwait的值,并非直接判断出这个CPU在等待IO。这两者的区别比较小。CPU是否在等待IO是通过nr_iowait来判断的。这个值是通过在系统调度过程中被设置,且统计块IO的情况。IOwait高代表着系统持续有IO执行,且CPU空闲,并不代表磁盘性能弱。因此,当IOwait过高时,还需要根据其他参考比如硬盘的带宽、响应时间等等进行判断是否真是块IO是一个瓶颈。相反的,当前CPU利用率非常高,而某个进程确实由于在等待IO而被失眠,iowait体现不出来。