1.概述
大家经常对一个系统的容量进行评估时,会参考cpu.idle和cpu.load指标,但是这两个指标到底在什么区间,表示系统是正常或者异常呢,业内有不同的说法。因此本文搜集一些资料,并对一个系统进行压测,最终来获得一个比较客观的观点,如有不对,可以在评论区进行交流。
在开始之前,我们必须对系统运转有一个整体的认识。在Linux内核中,每个进程都会被分配一个固定的时间片,默认为10ms,在这10ms中,该进程享有cpu的所有权。10ms看上去很短,但以2.6GHz的Intel处理器为例,10ms能够处理5000w条指令,对于绝大多数的应用这已经足够长了。如果该进程用完了10ms,或者有其他优先级高的进程发出请求,系统会触发一个中断,内核重新接管cpu,内核分配cpu给其他进程。10ms的分片让用户,也就是我们觉得我们的系统运转非常流畅,尽管我们可能同时开了很多的应用。
2.cpu.idle
CPU利用率主要分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间,三者之和就是CPU的总时间,当没有用户进程、系统进程等需要执行的时候,CPU就执行系统缺省的空闲进程。CPU的利用率就是指非空闲进程占用时间的比例,即CPU执行非空闲进程的时间 / CPU总的执行时间。
/proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取/proc目录中的文件时,proc文件系统是动态从系统内核读出所需信息并提交的。
cpu.idle是基于/proc/stat计算出来的,首先了解一下/proc/stat的各项指标的意义。
[xietao02@gh-trip-open-opengateway-staging01 ~]$ cat /proc/stat
cpu 30512019 2905 18888929 5215060855 449961 258 322293 482253 0
cpu0 12054132 723 5666598 1297356736 439476 258 173174 175261 0
cpu1 6256562 718 4332274 1305529992 4073 0 50163 105721 0
cpu2 6252205 723 4470475 1305772598 3466 0 49552 102278 0
cpu3 5949118 739 4419581 1306401527 2944 0 49403 98992 0
intr 10488180092 119 7 0 0 0 0 0 0 1 0 0 33 104 0 0 68 0 0 0 0 0 0 0 0 0 10319942 0 336 0 18155452 0 14 0 265289852 3907 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 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 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 18254375560
btime 1516246663
processes 13216259
procs_running 1
procs_blocked 0
softirq 3948723530 0 1488253637 8488 455883603 17 0 179 392363322 13619548 1598594736
第一行的数值表示的是CPU总的使用情况,cpu0、cpu1、cpu2、cpu3分别指每个cpu核心的cpu使用情况,下表解析第一行各数值的含义(单位:jiffies):
user (30512019) |
从系统启动开始累计到当前时刻,用户态的CPU时间,不包含nice值为负进程。 |
nice (2905) |
从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间 |
system (18888929) |
从系统启动开始累计当前时刻,核心时间 |
idle (5215060855) |
从系统启动开始累计到当前时刻,除IO等待时间以外其它等待时间 |
iowait (449961) |
从系统启动开始累计到当前时刻,IO等待时间 2.5.41版本新增字段 |
irq (258) |
从系统启动开始累计到当前时刻,硬中断时间 2.6.0版本新增字段 |
softirq (322293) |
从系统启动开始累计到当前时刻,软中断时间 2.6.0版本新增字段 |
stealstolen(482253) |
当一台物理机有多个虚拟机时,该cpu在其他虚拟机运行的时间 which is the time spent in other operating systems when running in a virtualized environment 2.6.11 |
guest(0) |
在cpu内核控制下,提供给在上面运行虚拟机占用的cpu时间 which is the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel 2.6.24 |
因为/proc/stat中的数值都是从系统启动开始累计到当前时刻的积累值,所以需要在不同时间点t1和t2取值进行比较运算,当两个时间点的间隔较短时,就可以把这个计算结果看作是CPU的即时利用率。
其他参数的含义
ctxt |
上下文切换次数 |
|
btime |
系统启动到当前的时间 |
sec |
process |
自启动以来,创建任务个数 |
|
procs_running |
当前运行任务个数 |
|
procs_blocked |
阻塞的任务个数 |
2.1 CPU的即时利用率的计算公式(top falcon命令显示的):
CPU在t1到t2时间段总的使用时间 = ( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2+stealstolen2+guest2) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1+stealstolen1+guest1)
CPU在t1到t2时间段空闲使用时间 = (idle2 - idle1)
CPU在t1到t2时间段即时利用率 = 1 - CPU空闲使用时间 / CPU总的使用时间
从top命令中看到的idle和falcon看到的cpu.idle都是以上的计算结果。
从falcon上看到的cpu.busy=1-cpu.idle。
2.2 CPU的平均利用率的计算公式(sar -u和ps aux命令显示的)
1-(当前时间对应的cpu.idle值 )/ (当前时间对应的cpu.total值),cpu.total就是cpu那一行所有项的加和。
2.3 进程和线程的cpu使用率
/proc目录中有一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程在/proc下都对应一个以进程号为目录名的目录/proc/pid,它们是读取进程信息的接口。此外,在Linux 2.6.0-test6以上的版本中/proc/pid目录中有一个task目录,/proc/pid/task目录中也有一些以该进程所拥有的线程的线程号命名的目录/proc/pid/task/tid,它们是读取线程信息的接口。
linux中的轻量级进程(lwp)即为线程,对应tid。
计算某一个进程和某一个线程的cpu利用率,和计算系统的cpu利用率类似。读取/proc/pid/stat或者读取/proc/pid/task/stat中的参数来进行计算。
3. cpu.load(系统平均负载,通过top、uptime、和falcon可以查看)
系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程数。如果一个进程满足以下条件则其就会位于运行队列中:
-
它没有在等待I/O操作的结果
-
它没有主动进入等待状态(也就是没有调用’wait’)
-
没有被停止(例如:等待终止)
在Linux中,进程分为三种状态,一种是阻塞的进程blocked process,一种是可运行的进程runnable process,另外就是正在运行的进程running process。
进程可运行状态时,它处在一个运行队列run queue中,与其他可运行进程争夺CPU时间。 系统的load是指正在运行和准备好运行的进程的总数。比如现在系统有2个正在运行的进程,3个可运行进程,那么系统的load就是5。
cpu.load是基于/proc/loadavg进行统计的。
查看系统平均负载使用“cat /proc/loadavg”命令,输出结果如下:
0.27 0.36 0.37 4/83 4828/
前三个指1、5、15分钟内的平均进程数(可以简单理解为每五秒统计一次,其实真实计算比较复杂。https://blog.csdn.net/jlds123/article/details/7617132)。后面两个指(正在运行的进程数/进程总数)和最近运行的进程ID号。
另外,通过"load average"中的三个数字,我们还可以了解到当前服务器的负载的变化趋势,如果1分钟的CPU负载 > 5分钟的CPU负载,说明服务器目前处在CPU负载高峰期;而如果1分钟的CPU负载 < 5分钟的CPU负载,则说明服务器的CPU负载高峰期刚刚过去了,如果是你处理了什么性能问题,则表明该处理已经显现成效了。
cpu.load大于多少没有性能够问题呢?
理想情况下cpu不空闲,但每个线程又都能及时获得cpu时间,没有等待的线程,任务处理完,紧接着出现另外一个可运行线程来获得cpu时间,此时cpu.load/cores=1。如果cpu.load过大则表示,有部分线程在等待获得cpu资源,过小表示cpu资源比较空闲。
对于cpu.load多少开始出现性能问题,外界有不同的说法,有的认为cpu.load/cores最好不要超过1,有的认为cpu.load/cores最好不要超过3,有的认为cpu.load不超过2*cores-2即可。
针对技术商服务进行压测时,发现load低时,接口TP999响应时间<50ms,而cpu.load/cores>4时,TP999响应时间约为200ms左右,多出来的时间可以理解为线程等待cpu处理的时间,可见cpu.load/cores过高时是影响接口响应时间的。
因此可以结合预期的接口响应时间,来定义每个服务的cpu.load/cores不超过多少。比如要求接口响应时间尽可能快的,最好确保cpu.load/cores不超过1,而对时间敏感性要求不太高时,一般要求cpu.load/cores不超过3。