查看原文
其他

服务端性能问题排查及优化---CPU高问题分析

Juny MiniStarClub北京 2019-12-10

双11又开始另一轮的性能测试,陆续给大家奉上性能测试系列篇,从性能测试理论、性能测试案例高延迟(响应时间长)、CPU问题、内存问题、线上问题实战和性能测试书籍推荐等篇章。


上次篇《服务端性能测试指标及问题排查》,主要从理论的角度阐述性能测试指标和性能测试排除过程,从本篇开始讲高延迟的案例,主要从原因、问题分析、案例等进行分析和讲解。




- 1 - 

 概述 

CPU高是常见的性能问题,但CPU高并不一定都是有问题,有可能你的业务就是CPU密集型的业务。

如果CPU资源有限的情况下,本文可以提供一下优化CPU使用的方法,可以尽可能的优化,使CPU在可能的范围内降到最低。

- 2 - 

 造成CPU问题的原因 

代码Bug

    可能性太多…

意外的死循环

    手抖写的死循环或者计算失误导致死循环

| 线程数太多(线程数量是否比预期的异常的高)

    大量的线程切换:线程数太多可能会导致频繁的线程上下文的切换,浪费CPU资源。

    频繁创建销毁线程:线程的创建和销毁对系统的资源消耗比较大,如果一直在频繁的创建销毁临时线程导致资源占用,可能需要考虑下是否有其他更好的方案了。

    线程池不正常的使用:比如Cache线程池初始化比较少、最小和最大的数量相差比较大、业务并发突然增大可能导致同时去创建线程。

频繁的FGC

    导致频繁的FGC也会导致CPU高,比如由于JVM参数设置的不合理,年轻代和老年代的比例比例不合理导致频繁的FGC等。

不正常的使用某些类

    比如Map的初始大小给的太小,而后续的使用中存的东西太多,可能会频繁的resize。

    比如大数据量List的频繁查找,clone等。

    比如可重复利用资源的频繁初始化操作。

- 3 - 

 CPU问题的分析过程 


用到的工具和命令

jvisualvm
jstack,jstat,jmap,ps,top

CPU高的几种情况

情况一:单核CPU使用率一直100%

大多情况为死循环或者某个线程一直在执行大量运算操作
情况二:单核CPU使用率不定时100%
应用本身有周期性的任务
非人为的周期性操作,比如FGC,大量数据的copy(list,map)
情况三:每核CPU使用率都高
需要结合堆栈、代码、资源占用、内存情况等,全面的考虑和分析。

分析方法

方法1
Java Visualvm直接连接进程分析,能够比较直观的看到每个方法所用的CPU时间,更容易定位问题。大多数情况下生产环境无法使用。适用于被测对象问题能够复现,且配置的远程rmi监控的情况。生产环境不会配置远程监控。
java服务启动时需配置启动参数:
-Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.143.136
使用方法见以下演示。
方法2
在CPU高的时候抓线程堆栈,适用于CPU相对比较高的情况,如果条件允许可以把服务压力加大到尽量大,使CPU尽量高后去分析问题。
抓取线程执行堆栈
jstack pid > /tmp/jstack.txt
找到占用cpu时间比较多的线程id
ps -mp pid -o THREAD,tid,time | awk '{printf $2" "$8"\n" }' | sort
把线程id转换为10进制,8进制?

printf "%x\n" tid

输出线程堆栈
jstack pid | grep –A 20 tid
连续抓取几次堆栈信息,分析正在运行的线程,分析当前操作是否耗费CPU,这么多运行的是否正常,业务堆栈是否正常,该业务可能出现的问题等等。

- 4 - 

 案例分析 

案例介绍

测试时发现使用的的测试客户端CPU高,表现为运行一段时间后,CPU突然100%,出现该情况后不能恢复正常。

分析过程

  1. 首先抓取客户端的线程堆栈,看看能否发现什么可以的地方。

  2. 分析堆栈发现线程有1000多,大部分为BLOCKED状态,ACTIVE状态基本看到的都是nio的,暂时没看到问题。

  3. 继续搜索本地package的以下名称,看看有没有在执行自己代码的地方,正好发现一些类似以下的信息。

Thread 1134: (state = IN_NATIVE)
- java.net.NetworkInterface.getAll() @bci=0 (Compiled frame; information may be imprecise)
- java.net.NetworkInterface.getNetworkInterfaces() @bci=0, line=334 (Compiled frame)
- com.alibaba.rocketmq.remoting.common.RemotingUtil.getLocalAddress() @bci=0, line=112 (Compiled frame)
- com.alibaba.rocketmq.client.ClientConfig.<init>() @bci=19, line=32 (Compiled frame)
- com.alibaba.rocketmq.client.producer.DefaultMQProducer.<init>(java.lang.String, com.alibaba.rocketmq.remoting.RPCHook) @bci=1, line=95 (Compiled frame)
- com.alibaba.rocketmq.client.producer.DefaultMQProducer.<init>(java.lang.String) @bci=3, line=86 (Compiled frame)
- ********************MQProducer.<init>(java.lang.String, java.lang.String) @bci=71, line=62 (Compiled frame)
- ********************.RocketMQ.sendMessage() @bci=76,line=119 (Compiled frame) // 119为源代码行号
- ********************.RocketMQ$1$1.safeRun() @bci=7, line=53 (Compiled frame)
- ********************.SafeRunnable.run() @bci=1, line=13 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=95, line=1145 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=615 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)
发现这些线程都在执行java.net.NetworkInterface.getAll() ,此方法比较耗费CPU,之前遇到过类似案例。接着分析为什么这几个线程会卡到这。
根据代码分析都在执行这个操作的原因。
public void sendMessage() {
try {
// 略…
Message msg = new Message("Performace", msgContent.getBytes("UTF-8"));
if (producer == null) {
producer = new MQProducer("Performace", "192.168.143.135:9876"); (1)
producer.start();
rst = producer.product(msg);
} else {
rst = producer.product(msg);
}
// 略…
} catch (Exception e) {
if (producer != null) {
producer.shutdown();
producer = null;
}
}
}
sendMessage方法会被随机的注册到一个timer线程池上,有可能会在同一时间点或者很近时间点同时执行该方法。
producer.product(msg);为给远端发送信息,如果因为网络原因或者其他未知原因导致Exception,会把producer赋值为null,当再次执行sendMessage会重新初始化producer,如果恰好有多线程并发执行sendMessage,可能会导致重复初始化以及其他并发问题,导致恶性循环,恰好这个过程对CPU消耗比较多。
以上是一个工作上简单案例的分析过程,实际工作中遇到的问题可能会复杂的多,过程可能会更曲折,需要从更多的方面去了解被测对象,甚至需要比开发自己更了解整个系统的架构,才能从多个方面去考虑问题,查找问题的真正原因

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存