平常的工作中,在衡量服务器的性能时,经常会涉及到几个指标,load、cpu、mem、qps、rt等。每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴随着某些指标的异常。大部分情况下,在问题发生之前,某些指标就会提前有异常显示。
在上一篇文章中,我们介绍了一个重要的指标就是负载(Load),其中我们提到Linux的负载高,主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多,都将导致服务器负载的急剧攀升。本文就来分析其中的第二项,CPU的利用率。主要涉及CPU利用率的定义、查看CPU利用率方式、CPU利用率飙高排查思路等。
CPU利用率,又称CPU使用率。顾名思义,CPU利用率是来描述CPU的使用情况的,表明了一段时间内CPU被占用的情况。使用率越高,说明你的机器在这个时间上运行了很多程序,反之较少。使用率的高低与你的CPU强弱有直接关系。
在接下来深入介绍CPU的利用率之前,我们先来解释一个简单的概念,可能是很多人一直存在误解的地方。
很多人都知道,现在我们用到操作系统,无论是Windows、Linux还是MacOS等其实都是多用户多任务分时操作系统。使用这些操作系统的用户是可以“同时”干多件事的,这已经是日常习惯了,并没觉得有什么特别。 但是实际上,对于单CPU的计算机来说,在CPU中,同一时间是只能干一件事儿的。为了看起来像是“同时干多件事”,分时操作系统是把CPU的时间划分成长短基本相同的时间区间,即"时间片",通过操作系统的管理,把这些时间片依次轮流地分配给各个用户使用。 如果某个作业在时间片结束之前,整个任务还没有完成,那么该作业就被暂停下来,放弃CPU,等待下一轮循环再继续做.此时CPU又分配给另一个作业去使用。 由于计算机的处理速度很快,只要时间片的间隔取得适当,那么一个用户作业从用完分配给它的一个时间片到获得下一个CPU时间片,中间有所"停顿",但用户察觉不出来,好像整个系统全由它"独占"似的。
而我们说到的CPU的占用率,一般指的就是对时间片的占用情况。
在上一篇文章中,我们介绍过,使用uptime
、top
、w
等命令可以在Linux查看系统的负载情况。其中,top
命令也可以用来查看CPU的利用率,除此之外,还可以使用vmstat
来查看cpu的利用率。
vmstat命令
vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。
1➜ ~ vmstat
2procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
3 r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 1 0 2446260 0 3202312 0 0 201 16304 1 6 0 0 84 5 1
从上面的结果中我们可以看到很多信息,我们本文重点关注下cpu部分的指标。
1us sy id wa st
20 0 84 5 1
以上几个指标是当前CPU的占用情况。
%us:用户进程执行时间百分比
us的值比较高时,说明用户进程消耗的CPU时间多,但是如果长期超50%的使用,那么我们就该考虑优化程序算法或者进行加速。
%sy:内核系统进程执行时间百分比
sy的值高时,说明系统内核消耗的CPU资源多,这并不是良性表现,我们应该检查原因。
%id:空闲时间百分比
%wa:IO等待时间百分比
wa的值高时,说明IO等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。
%st:虚拟 CPU 等待实际 CPU 的时间的百分比
一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数。
1➜ ~ vmstat 2 2
2procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
3 r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 0 2479444 0 3165172 0 0 196 15905 2 8 0 0 84 5 11
5 0 0 0 2479404 0 3165176 0 0 0 2804 81664 2715 0 0 90 1 9
以上命令表示采集两次数据,每隔2秒采集一次。
top命令
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。
1~ top
2top - 10:58:07 up 18:13, 1 user, load average: 0.32, 0.24, 0.19
3Tasks: 64 total, 1 running, 63 sleeping, 0 stopped, 0 zombie
4Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 92.8%id, 0.1%wa, 0.0%hi, 0.0%si, 6.8%st
5Mem: 8388608k total, 5928076k used, 2460532k free, 0k buffers
6Swap: 16777216k total, 0k used, 16777216k free, 3181996k cached
7 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8 2393 admin 20 0 5056m 2.2g 56m S 4.3 27.6 79:06.21 java
9 1054 root 20 0 338m 9760 5112 S 0.3 0.1 2:37.30 logagent
使用top命令,除了可以查看Load Avg以外,还可以显示CPU利用率信息。
以上top命令打印的信息中(Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 92.8%id, 0.1%wa, 0.0%hi, 0.0%si, 6.8%st),第三行反映了当前cpu的整体情况。
从上面的打印信息中我们还可以看到,ID为2393的java进程当前内存使用率最高,占到4.3%左右。
由于Java是多线程的,所有,有些时候我们希望可以查看一个Java进程中所有线程的cpu使用率如何,也可以使用top命令来查看。
1➜ ~ top -Hp 1893
2PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
319163 admin 20 0 5056m 2.2g 56m S 1.7 27.6 17:39.97 java
410649 admin 20 0 5056m 2.2g 56m S 0.7 27.6 4:07.64 java
55884 admin 20 0 5056m 2.2g 56m S 0.3 27.6 2:18.19 java
610650 admin 20 0 5056m 2.2g 56m S 0.3 27.6 1:24.77 java
通过top -Hp 1893
命令,我们可以发现,当前1893这个进程中,ID为19163的线程占用CPU最高,达到1.7%左右。
PS:top命令的输出结果是动态的,随着系统的情况实时变化的。
CPU使用率的计算逻辑描述系统cpu使用情况主要有一下几点:
user 从系统启动到现在,CPU处于用户态的运行时间。不包含nice值为负的进程。
nice 从系统启动到现在,CPUnice为负值的进程占用的cpu时间。
system 从系统启动到现在,CPU处于内核态的运行时间。
idle 从系统启动到现在,CPU除了 iowait外的等待时间。
iowait 从系统启动到现在,CPUio 等待时间。
irq 从系统启动到现在,CPU硬中断花费的时间。
softirq 从系统启动到现在,CPU软中断花费的时间。
steal 从系统启动到现在,CPU运行其他虚拟环境中的操作系统花费的时间。
guest 从系统启动到现在,CPU运行在通过Linux内核控制的客户操作系统上的虚拟cpu的时间。
guest_nice 从系统启动到现在,CPU运行在通过Linux内核控制的客户操作系统上的虚拟cpu的时间, nice 为负值进程。
知道了以上参数的意思,计算某段时间内的cpu使用率就不难,由于cpu资源是在高速的变化,于是计算cpu使用率只能是在一段时间内的,设置两个时间点为t1和t2, CPU在t1和t2时间内总的使用时间:
1( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2 + steal2 + guest2 + guest_nice2 ) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1 + steal1 + guest1 + guest_nice1)
CPU的空闲时间:
1(idle2 -idle1)
CPU在t1和t2时间内的使用率
1CPU非空闲时间/CPU总时间*100%=(1-CPU的空闲时间/CPU总时间)*100%
则:
1CPU(t1,t2)使用率:1-(idle2-idle1)/(( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2 + steal2 + guest2 + guest_nice2 ) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1 + steal1 + guest1 + guest_nice1))
(参考资料:https://blog.csdn.net/IT_DREAM_ER/article/details/52037368)
CPU利用率和负载我们上一篇文章介绍了系统的负载,本文介绍了CPU利用率,很多小伙伴就会分不清楚了,这两者之前到底有什么区别和联系呢?
CPU利用率
是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况。
CPU负载
是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。
有一个很好的比喻,就是把CPU的使用比喻成排队打电话:
我们将CPU就类比为电话亭,每一个进程都是一个需要打电话的人。现在有一个电话亭(单核计算机),有10个人需要打电话(10个进程)。现在使用电话的规则是管理员会按照顺序给每一个人轮流分配1分钟的使用电话时间,如果使用者在1分钟内使用完毕,那么可以将电话使用权返还给管理员,如果到了1分钟电话使用者还没有使用完毕,那么需要重新排队,等待再次分配使用。在电话亭使用过程中,肯定会有人打完电话走掉,有人没有打完电话而选择重新排队,同样也会有新来的人继续排队,这个人数的变化就相当于任务数的增减。
CPU的Load统计一定时间段内,所有使用电话的人加上等待电话分配的人数的平均值。为了统计平均负载情况,我们5分钟统计一次人数,并在第1、5、15分钟的时候对统计情况取平均值,从而形成第1、5、15分钟的平均负载。
CPU利用率统计的进程在进入电话亭后,真正使用电话的时间和在电话亭停留的时间的比值。例如一个用户得到了一分钟的使用权,在10秒钟内打了电话,然后去查询号码本花了20秒钟,再用剩下的30秒打了另一个电话。那么他的利用率就是(10+30)/60
当发现系统的CPU使用率飙高时,首先要定位到是哪个进程占用的CPU较高。一般情况下,对于Java代码来说,导致CPU飙高可能由以下几个原因引起:
1、内存泄露、导致大量Full GC(如典型的Java 1.7之前的String.subString
导致的内存泄露问题) 2、代码存在死循环(如典型的多线程场景使用HashMap
导致死循环的问题)
这部分问题排查思路其实和我上一篇问文章的思路差不多,基本都是先定位到占用CPU较多的进程和线程,然后通过命令在查看这条线程执行情况。通过分析代码来定位其中的问题。
这里就不重复介绍了,最重要的是熟练的使用jstack
、jstat
以及jmap
等命令来定位及解决Java进程的问题。