为了全面详细的分析系统运行状态,发现隐藏的性能瓶颈。性能测试期间,全面监视CPU运行状态是很有必要的。
本文侧重分析性能测试期间需要监控的CPU运行状态指标,对比相关查询命令的优劣,并给出最终的shell脚本。
关于各指标的详细含义,见附件。
1、load average,平均每个逻辑内核不能高于0.7。
load average大于1,表示系统中存在处于等待状态的任务,任务竞争CPU容易导致性能降低,时延增大,甚至进入恶性循环。在一个合理的load average下加压,监测CPU使用率的变化情况,可以帮助发现I/O、内存、网络中的性能瓶颈。
2、CPU总占有率。总占有率小于70%,其中以%usr为主,%sys和%iowait不能太高。
3、各逻辑内核CPU占有率持平。
4、执行相同任务的进程CPU占有率持平。
5、进程状态合理,僵死进程不能太多。
数据收集的重点与核心在于:
详实而又不冗余,不关注无关指标,以最少的数字反应关注的指标。
有的指标项,比如各逻辑内核的CPU占有率持平,关注的是一组数据的分布特点,而不关心数据的具体值。同时,当前系统性能的瓶颈主要在I/O。数据收集期间记录全部数据的具体数值,即降低影响系统性能,又加大了后期数据处理的工作量。
故,数据收集之前,对我们所需要的数据的统计特征进行分析。
每隔1min,5min或15min取该段时间内的load average即可。一次取1个数据。
shell命令:uptime | awk -F: '{print $NF}'|awk -F, '{print $1}'
命令解释:
uptime获取load average。
awk -F: '{print $NF}'提取1min,5min或15min 内load average的具体数值。
awk -F, '{print $1}'提取其中1个字段。
每隔一段时间,取当前的%usr,%sys,%iowait,%idle取值。
shell命令:mpstat|grep all
解释:mpstat的输出参数,无法自定义字段。其中部分字段是我们暂时不关注,但后续会关注。另外,剔除这些字段涉及较多的管道和文本分析,较为复杂。同时,降低了脚本的可移植性。
根据各逻辑内核的CPU占有率计算:跨度((max-min)/average),mdev(sqrt(平方和的平均值-平均值的平方))
命令:
mpstat -P ALL|grep -v -i ALL|grep -o -e '[0-9][0-9]*\..*\.[0-9]*[0-9]$'|awk -v col=9 -f cal.awk
其中用到了脚本 cal.awk
解释:
mpstat -P ALL|grep -v -i ALL|grep -o -e '[0-9][0-9]*\..*\.[0-9]*[0-9]$' 提取各CPU的指标的数据。
col=9,列数。
cal.awk脚本计算数据值的跨度和mdev
BEGIN {
for(i=1;i<=col;i++){
sum[i] = 0;
squsum[i] = 0;
max[i] = 0;
min[i] = 1000000;
}
}
{
for(j=1;j<=col;j++) {
tmp = $j
sum[j] += tmp
squsum[j] += tmp*tmp
if(max[j]
max[j] = tmp
if(min[j]>tmp)
min[j] = tmp
}
}
END {
for(k=1;k<=col;k++) {
ave = sum[k]/NR
mdev = sqrt(squsum[k]/NR-ave*ave)
printf("%.2f/%.2f/%.2f/%.2f "), ave,max[k],min[k],mdev
}
}
算法同上。
命令:
# ps aux |grep nginx|grep -v grep|awk '{print $3}'|awk -v col=1 -f cal.awk
ave/max/min/mdev = 2.59/3.00/0.00/0.92
定时(每分钟)输出cpu运行状态信息到指定文件(cpu_yjk.log)。
为了方便后续用python进行数据分析,输出格式统一如下:
1、每次输出独占且只占用一行。
2、数据项之间以“,”分隔。
3、涉及统计数字的数据项,以ave/max/min/mdev格式输出计算结果
#!/bin/bash
sleepTime=60
logfile=cpu_yjk.log
if [ -f "$logfile" ];
then
rm cpu_yjk.log
fi
exec 1>$logfile
processName="watchCpu.sh"
title="load"
coretitle=`mpstat | grep -o -e '%.*'`
#print title
printf "%s," `date +%Y-%m-%d_%H:%M:%S`
printf "%6s," $title
printf "%12s(ave/max/min/mdev)," $coretitle
printf "%12s(ave/max/min/mdev)," $processName
printf "\n"
while true
do
load=`uptime | awk -F: '{print $NF}'|awk -F, '{print $1}'`
corevalue=`mpstat -P ALL|grep -v -i ALL|grep -o -e '[0-9][0-9]*\..*\.[0-9]*[0-9]$'|awk -v col=9 -f cal.awk`
processValue=`ps aux |grep $processName|grep -v grep|awk '{print $3}'|awk -v col=1 -f cal.awk`
#print value
printf "%s," `date +%Y-%m-%d_%H:%M:%S`
printf "%6.2f," $load
printf "%30s," $corevalue
printf "%30s," $processValue
printf "\n"
sleep $sleepTime
done
Load:简单的说是进程队列的长度(WikiPedia:the system Load is a measure of the amount of work that a compute system is doing)。
Load Average:一段时间(1分钟、5分钟、15分钟)内平均Load。
即一段时间内正在使用和等待使用CPU的统计信息(平均任务数)。
Unix系统,队列长度主要看:正在执行的进程数、等待的进程数。
Linux系统,在Unix之上增加不可中断的进程数。
uptime: load average后的三个数字依此是过去1min,5min,15min的平均负载。
w:同时显示已登录的用户。打开2个shell标签页,显示两个shell端。
cat /proc/loadavg
top:占用资源较多,不适合写入脚本。
tload 画图形
procinfo: ubuntu 12.04 需要单独安装。Suse系统默认没有安装。
单个CPU核心上的负载为1,表示表示系统没有剩余资源,同时恰好没有等待资源。
但是,任何的异常都会导致出现排队等待序列,进入恶性循环。
一般认为,单核的理想附负载值为0.7,也有0.5-0.6一说。
若多个CPU,则计算每个CPU逻辑核心的平均值。
多核处理器的理想负载值:0.7*逻辑CPU个数。
逻辑CPU个数查看命令:grep 'model name' /proc/cpuinfo | wc -l
CPU使用率从以下3个方面监控:
1、具体进程的CPU占有率及其随时间的变化规律(纵向对比)。
不能超过特定数值或百分比。
2、各CPU独立内核CPU占有率分配情况(横向对比)。
横向分配均匀。
主要有sar,mpstat,vmstat,top。
其中,top消耗资源较多,不适合在性能期间持续运行。
mpstat可以查看各个CPU核心的负载情况,可以设定刷新时间和次数。比较适合。
linux198:~ # sar 1 3
Linux 2.6.16.46-0.12-smp (linux198) 07/26/12
18:03:41 CPU %user %nice %system %iowait %idle
18:03:42 all 14.76 0.00 4.09 0.00 81.14
18:03:43 all 13.95 0.00 1.99 0.25 83.81
18:03:44 all 9.31 0.00 5.58 1.36 83.75
Average: all 12.67 0.00 3.89 0.54 82.90
linux39:~ # mpstat -P ALL 3 4
Linux 2.6.16.46-0.12-smp (linux39) 07/26/12
15:35:37 CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s
15:35:40 all 2.24 0.00 1.29 0.04 0.04 1.41 0.00 94.97 7645.70
15:35:40 0 0.33 0.00 0.33 0.00 0.00 0.00 0.00 99.34 0.00
15:35:40 1 1.66 0.00 1.32 0.00 0.00 0.99 0.00 96.36 1527.81
15:35:40 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.34 5.96
15:35:40 3 6.62 0.00 2.32 0.00 0.00 4.30 0.00 86.75 2905.63
15:35:40 4 0.33 0.00 0.66 0.00 0.00 0.00 0.00 98.68 0.00
15:35:40 5 0.66 0.00 0.33 0.66 0.00 0.33 0.00 97.68 109.27
15:35:40 6 8.28 0.00 5.63 0.00 0.00 5.96 0.00 80.46 2807.95
15:35:40 7 0.33 0.00 0.33 0.00 0.00 0.00 0.00 98.68 289.40
linux198:~ # vmstat 1 3
procs -----------memory---------- - --swap-- -----io---- -system- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 4499660 10534364 29408 1725604 0 1 12 14 1 3 23 5 72 0 0
3 0 4499660 10549164 29408 1715324 0 0 0 48 2847 12769 29 12 59 0 0
1 0 4499660 10549500 29408 1715324 0 0 0 0 2157 12800 16 3 81 0 0
Procs
r: The number of processes waiting for run time.即load average
CPU
These are percentages of total CPU time.
us: Time spent running non-kernel code. (user time, including nice time)
sy: Time spent running kernel code. (system time)
id: Time spent idle. Prior to Linux 2.5.41, this includes IO-wait time.
wa: Time spent waiting for IO. Prior to Linux 2.5.41, shown as zero.
st: Time spent in involuntary wait. Prior to Linux 2.6.11, shown as zero.
分析%usr :%sys :%wio的情况,
%usr是指CPU用于执行应用程序百分比,
%sys是指CPU应用执行系统程序(通常是操作系统的系统调用)的百分比,
%wio是指CPU在等待IO的百分比。
通常情况下,%sys和%wio都不应该太高,否则就说明应用程序设计不合理,需要分析原因。
完成同样功能的应用程序,其CPU占用率应该大致相等,否则说明系统负荷分配不均匀。
对于多CPU的系统,各CPU的占用率也应该大致相等,否则说明系统对CPU资源的使用不均衡,需要优化配置。
总的CPU平均占用率不应该太高,如超过90%,否则说明可能系统性能已经受限于CPU资源。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 780 76 ? S Jul13 0:09 init [3]
root 2 0.0 0.0 0 0 ? S Jul13 0:00 [migration/0]
root 3 0.0 0.0 0 0 ? SN Jul13 0:00 [ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S Jul13 0:00 [migration/1]
root 5 0.0 0.0 0 0 ? SN Jul13 0:00 [ksoftirqd/1]
root 6 0.0 0.0 0 0 ? S Jul13 0:00 [migration/2]
root 7 0.0 0.0 0 0 ? SN Jul13 0:00 [ksoftirqd/2]
linux上进程有5种状态:
1. 运行(正在运行或在运行队列中等待)
2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)
3. 不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
4. 僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)
5. 停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)
ps工具标识进程的5种状态码:
D 不可中断 uninterruptible sleep (usually IO)
R 运行 runnable (on run queue)
S 中断 sleeping
T 停止 traced or stopped
Z 僵死 a defunct ("zombie") process
注: 其它状态还包括W(无驻留页), <(高优先级进程), N(低优先级进程), L(内存锁页).
性能测试期间,不能有大量僵死进程。
完成同样功能的进程,CPU占有率相近。
关键进程运行状态正常,CPU占有率正常。是否需要特定进程的实时CPU占有率?个人认为不需要,因为,端到端场景中,往往需要多个进程之间协作,关心特定进程的占有率意义不大,关心全部进程占有率工作量太大且无明显意义。只要保证进程状态正常,CPU整体占有率合适且各内核占有率均衡即可。
所以,命令上选择:mpstat和ps aux
/proc/cpuinfo查看cpu的参数信息,性能测试时主要关心逻辑内核总数。
processor 条目包括这一逻辑处理器的唯一标识符
physical id相同的是同一个物理CPU。
core id相同的是同一个核的超线程。
siblings 条目列出了位于相同物理封装中的逻辑处理器的数量。
# cat /proc/cpuinfo | grep “processor” | wc -l
# cat /proc/cpuinfo | grep “physical id” | sort | uniq | wc -l
# cat /proc/cpuinfo | grep “cpu cores” | wc -l
如果有两个逻辑CPU具有相同的”core id”,那么超线程是打开的。
# cat /proc/cpuinfo | grep “siblings”
逻辑CPU个数:cat /proc/cpuinfo | grep "processor" | wc -l
物理CPU个数:cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l
“siblings”指的是一个物理CPU有几个逻辑CPU
”cpu cores“指的是一个物理CPU有几个核
不应该按照flags里是否有 ht 标志来判断系统是否有超线程能力,而应该:
如果“siblings”和“cpu cores”一致,则说明不支持超线程,或者超线程未打开。
如果“siblings”是“cpu cores”的两倍,则说明支持超线程,并且超线程已打开。
# cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
2 Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
(看到有2个逻辑CPU, 也知道了CPU型号)
# getconf LONG_BIT
32
(说明当前CPU运行在32bit模式下, 但不代表CPU不支持64bit)
# cat /proc/cpuinfo | grep flags | grep ' lm ' | wc -l
2
(结果大于0, 说明支持64bit计算. lm指long mode, 支持lm则是64bit)
#lscpu
Architecture: i686 #架构686
CPU(s): 2 #逻辑cpu颗数是2
Thread(s) per core: 1 #每个核心线程数是1
Core(s) per socket: 2 #每个cpu插槽核数/每颗物理cpu核数是2
CPU socket(s): 1 #cpu插槽数是1
Vendor ID: GenuineIntel #cpu厂商ID是GenuineIntel
CPU family: 6 #cpu系列是6
Model: 23 #型号23
Stepping: 10 #步进是10
CPU MHz: 800.000 #cpu主频是800MHz
Virtualization: VT-x #cpu支持的虚拟化技术VT-x
L1d cache: 32K #一级缓存,具体为L1数据缓存为32k
L1i cache: 32K # 一级缓存,具体为L1指令缓存为32K
L2 cache: 3072K #二级缓存3072K