假如生产环境出现CPU占用过高,请谈谈你的分析思路和定位?
曾经年少的我碰到这种问题,答案会脱口而出:“看日志”。
然后就是回家漫长的等通知。
- 一个 while 死循环,会不会引起 CPU 使用率飚升?
- 频繁 Young GC 会不会引起 CPU 使用率飚升?
- 线程数很高的应用,CPU 使用率一定高么?
- CPU 使用率高的应用,线程数一定高么?
- BLOCKED 状态的线程会不会引起 CPU 使用率飚升?
- 分时操作系统 CPU 是耗费 us ? 还是耗费 sy ?
1、CPU 使用率怎么计算?
CPU% = 1 - idleTime / sysTime * 100
- idleTime:CPU处于空闲状态的时间
- sysTime:CPU处于用户态和内核台的时间总和
2、CPU 使用率跟啥有关系?
常听说计算密集型的程序是比较耗 CPU 使用率的。
那 JAVA 应用中哪些操作是比较耗 CPU 使用的?
列举日常程序中常见的耗CPU的操作:
- 频繁GC,访问量高时,有可能造成频繁的GC、甚至FGC。当调用量大时,内存分配过快,就会造成GC线程不停的执行,导致CPU飙高
- 序列化与反序列化,后文中举了一个真实的案例,程序执行xml解析的时,调用量增大的情况下,导致了CPU被打满
- 加密、解密
- 正则表达式校验,曾经线上发生一次血案,正则校验将CPU打满。大概原因是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种引擎在进行字符匹配会发生回溯(backtracking)
- 线程上下文切换、当启动了很多线程,而这些线程都处于不断的阻塞状态(锁等待、IO等待等)和执行状态的变化过程中。当锁竞争激烈时,很容易出现这种情况
- 某些线程在做无阻塞的运算,简单的例子while(true)中不停的做运算,没有任何阻塞。写程序时,如果需要做很久的计算,可以适当将程序sleep下
3、CPU 与进程、线程有关系么?
现在分时操作系统是通过循轮方式分配时间片进行进程调度的,如果进程在等待或阻塞,不会造成 CPU 资源使用。线程称为轻进程,共享进程资源,关于线程的调度,CPU 对于线程也是分时调度。而在 Java 中,线程的调用由 JVM 负责,线程的调度一般有两种模式,分时调度和抢占式调度。
解惑
1、一个 while 死循环,会不会引起 CPU 使用率飚升?
会的。
先不说别的,死循环会调用 CPU 寄存器进行计数,这个操作就会占用 CPU。其次,如果线程一直处于死循环状态,CPU 调用会进行线程切换么?
死循环不会让出 CPU,除非操作系统时间片到期,但死循环会不断向系统申请时间片,直到系统没有空闲时间做别的事情。
这个问题在 stackoverflow 也有人提问:why does an infinite loop of the unintended kind increase the CPU use?
2、频繁 Young GC 会不会引起 CPU 使用率飚升?
会的。
Young GC 本身是 JVM 进行垃圾回收的操作,会计算内存和调用寄存器,频繁 Young GC 一定是会占用 CPU。
之前有个一个案例,for 循环从数据库查询数据集合,二次封装新的数据集合,这时如果量比较大时,内存没有足够的空间存储,那么 JVM 就会 GC 回收那些不再使用的数据,因此量大的时候,就会收到 CPU 使用率报警。
3、线程数很高的应用,CPU 使用率一定高么?
不会。
通过 jstack 查看系统线程状态,查看整个线程数很多,但 Runable 和 Running 状态的线程不多,这时 CPU 使用率不一定会高。
之前有过一个案例,查看系统线程数 1000+,jstack 分析 900多个线程是 BLOCKED 和 WAITING 状态的,这种线程是不会占用 CPU 的。
如果线程数很高,其实大多数原因是死锁,大量线程处于 BLOCKED 和 WAITING 状态。
4、CPU 使用率高的应用,线程数一定高么?
不会。
同上,CPU 使用率高的关键因素还是计算密集型操作,一个线程如果有大量计算,也会造成 CPU 使用率高,也是现在为什么一个大数据脚本任务,要大规模集群共同运算才能运行的原因。
5、BLOCKED 状态的线程会不会引起 CPU 使用率飚升?
不一定。
CPU使用率的飙升,更多是因为上下文的切换或者runnable状态线程过多导致。Blocked状态,未必会引起CPU上升。
6、分时操作系统 CPU us高或者sy高是什么意思?
通过top命令,可以观察到CPU的us,sy值,示例如下:
- us 用户空间占用CPU百分比,简单来说,us高是因为程序导致的,通过分析线程堆栈,可以很容易的定位到问题线程。
- sy 内核空间占用CPU百分比,sy高的时候,如果是程序问题导致,基本是因为线程上下文切换造成的。
平时怎么定位 CPU 使用率高的原因?网上有个教程和方法,下面简述一下分析过程。
首先发现某台应用 CPU 使用率高,一要看先线程数、JVM、系统 load 等参数,共同作证。二要打印 jstack,通过工具分析线程情况,推荐 fastThread 这个在线的 Thread 分析工具。
以下是线上发生的真实案例,简要介绍下:
某日晚,突然收到短信报警,CPU利用率100%。立刻dump该机器jstack,通过 http://fastthread.io/ 查看日志如下:
进一步查看具体日志:
通过这段日志,已经定位到了具体CPU被打满的方法,接收MQ之后,MQ消息体为xml,反序列化的时候,造成了CPU飙高。
Linux中我们常用mpstat、vmstat、iostat、sar和top来查看系统的性能状态。
mpstat: mpstat是Multiprocessor Statistics的缩写,是实时系统监控工具。其报告为CPU的一些统计信息,这些信息存放在/proc/stat文件中。在多CPUs系统里,其不但能查看所有CPU的平均状况信息,而且能够查看特定CPU的信息。mpstat最大的特点是可以查看多核心cpu中每个计算核心的统计数据,而类似工具vmstat只能查看系统整体cpu情况。
vmstat:vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令,一个是Linux/Unix都支持,二是相比top,我可以看到整个机器的CPU、内存、IO的使用情况,而不是单单看到各个进程的CPU使用率和内存使用率(使用场景不一样)。
iostat: 主要用于监控系统设备的IO负载情况,iostat首次运行时显示自系统启动开始的各项统计信息,之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。
sar: sar(System Activity Reporter系统活动情况报告)是目前 Linux 上最为全面的系统性能分析工具之一,可以从多方面对系统的活动进行报告,包括:文件的读写情况、系统调用的使用情况、磁盘I/O、CPU效率、内存使用状况、进程活动及IPC有关的活动等。
top:top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。top显示系统当前的进程和其他状况,是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止。比较准确的说,top命令提供了实时的对系统处理器的状态监视。它将显示系统中CPU最“敏感”的任务列表。该命令可以按CPU使用。内存使用和执行时间对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定。
除了服务器硬件的性能瓶颈,对于MySQL系统本身,我们可以使用工具来优化数据库的性能,通常有三种:使用索引,使用 EXPLAIN 分析查询以及调整 MySQL 的内部配置。
在这个代表爱情的日子里,我正憧憬着怎么赶紧写完下午的bug,早早下班回家的时候,突然收到一封系统邮件,大致意思是“有一台机器CPU使用太高了”,打开监控平台,果然
.png)
遇到问题,我没有丝毫慌张,不紧不慢的登录服务器,只是简单的输入了3个英文字母:top
如下,果然看到有一个java进程CPU的使用率竟然达到了325%
ps -ef 或者 jps -l 进一步定位具体对应的pid,看看是一个什么进程
定位到具体线程(tid)
ps -mp pid -o THREAD,tid,time
参数解释:
- -m 显示所有进程
- -p pid 进程使用 cpu 的时间
- -o 该参数后是用户自定义格式
或者通过top -H -p pid ,直接找到CPU使用率比较高的一些线程
这两种方式均可以看到CPU使用率最高的线程都是20817
因为线程在内存中跑是 16 进制的,将需要的线程 ID 转换为 16进制格式(英文小写格式 )
printf '%x\n' tid(tid是有问题的线程ID),这一步也可以用计算器换算下
通过jstack查看该线程的栈信息
jstack pid | grep nid -A100 (nid是16进制的线程ID,-A100表示打印前100行)


