性能文章>CPU性能篇:CPU使用率100%,应该怎么办>

CPU性能篇:CPU使用率100%,应该怎么办原创

2年前
454348

在上一篇文章中,我们介绍了一个重要的指标就是负载(Load),其中我们提到Linux的负载高,主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多,都将导致服务器负载的急剧攀升。本文就来分析其中的第二项,CPU的利用率。主要涉及CPU利用率的定义、查看CPU利用率方式、CPU利用率飙高排查思路等。

什么是CPU利用率

CPU利用率,又称CPU使用率。顾名思义,CPU利用率是来描述CPU的使用情况的,表明了一段时间内CPU被占用的情况。使用率越高,说明你的机器在这个时间上运行了很多程序,反之较少。使用率的高低与你的CPU强弱有直接关系。

在接下来深入介绍CPU的利用率之前,我们先来解释一个简单的概念,可能是很多人一直存在误解的地方。

很多人都知道,现在我们用到操作系统,无论是Windows、Linux还是MacOS等其实都是多用户多任务分时操作系统。使用这些操作系统的用户是可以“同时”干多件事的,这已经是日常习惯了,并没觉得有什么特别。 但是实际上,对于单CPU的计算机来说,在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))


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

Java Web应用CPU使用率飙高排查思路

当发现系统的CPU使用率飙高时,首先要定位到是哪个进程占用的CPU较高。一般情况下,对于Java代码来说,导致CPU飙高可能由以下几个原因引起:
1、内存泄露、导致大量Full GC(如典型的Java 1.7之前的String.subString导致的内存泄露问题)
2、代码存在死循环(如典型的多线程场景使用HashMap导致死循环的问题)

这部分问题排查思路其实和我上一篇问文章的思路差不多,基本都是先定位到占用CPU较多的进程和线程,然后通过命令在查看这条线程执行情况。通过分析代码来定位其中的问题。

这里就不重复介绍了,最重要的是熟练的使用jstack、jstat以及jmap等命令来定位及解决Java进程的问题。

点赞收藏
Hollis

Hollis,一个对Coding有着独特追求的人。现任阿里巴巴技术专家,《程序员的三门课》联合作者。

请先登录,查看4条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

JDBC PreparedStatement 字段值为null导致TBase带宽飙升的案例分析

JDBC PreparedStatement 字段值为null导致TBase带宽飙升的案例分析

随机一门技术分享之Netty

随机一门技术分享之Netty

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

8
4