全链路监控分析实战(二)
告别野路子,
性能大牛锤炼之路从这里开始

面试性能岗位必问知识点:
最最常见的性能瓶颈话题:
无论给服务器多大压力,服务器的CPU利用率始终很低,吞吐量一直上不去?如果瓶颈是由于代码问题导致的,请问如何定位?
1、压测服务器
单场景压测被测系统的登录接口,压力曲线模型如下:
压测策略:
施压20个线程,每30秒增加2个线程,重点关注压力增加的这段。
监控平台:
grafana+prometheus+node_exporter+influxdb

2、性能指标监控

基本分析:压力在不断增大(上图右侧曲线),但吞吐量却始终保持在2.6/s(上图左侧曲线),非常的小,而响应时间(上图下方曲线)却在快速变长,性能瓶颈明显地暴露出来。
再来看一下操作系统的资源消耗情况,如下图,cpu的利用率非常低,接下来进行代码瓶颈定位。

3、JVM核心知识梳理
如果对这些JVM的核心知识完全不懂,也不愿意进一步研究,要么果断放弃,要么看之前的系列文章。下面这些知识不难,但是必须懂哦!
栈是线程私有的,堆是线程共享的
栈是运行时单位,堆是存储单位
栈解决程序运行问题,堆解决数据存储问题
堆中存的是对象,栈中存的基本数据类型和堆中对象的引用
栈代表了处理逻辑,而堆代表了数据
栈空间不足抛出异常:java.lang.StackOverflowError
堆空间不足抛出异常:java.lang.OutOfMemoryError
线程是cpu的基本执行单元,而线程的执行信息又存储在栈空间里,所以我们对cpu资源的分析核心就是栈数据的分析,也就是经常说的对线程做dump(拍快照)。
cpu常见的瓶颈主要有两种:
cpu资源很容易被消耗掉,导致cpu资源利用率超高
不管给多大压力,cpu的资源利用率总是上不去
这些问题分析的入口基本都是对栈的分析,所以栈善于分析如下问题:
系统无缘无故cpu过高
系统挂起,无响应
系统运行越来越慢
性能瓶颈,如无法充分利用cpu等
线程死锁、死循环,饿死等
线程数量太多导致系统失败,如无法创建线程等
4、瓶颈问题分析
压力上不去,抛开其它因素,假设就是代码的问题,说明线程被阻塞了,得不到cpu的执行。在Java虚拟机层面,线程的状态主要有:阻塞、等待、休眠、可运行。敲重点:只有处于可运行状态的线程才可能消耗cpu,处于其它状态的线程对cpu几乎都没有压力。而现在的瓶颈就是cpu没压力呀,所以通过分析线程栈就可以知道线程正在做的事情了。
5、借助工具查找瓶颈
最强悍的工具终于上场了——arthas,官方帮助文档:https://arthas.aliyun.com/doc/,详细的功能和使用上面说的非常清楚,如果有实在理解不了的,加微信交流:13401182883。
1)下载
登录被测服务器,在命令行下输入命令:
wget https://arthas.aliyun.com/arthas-boot.jar
2)启动压测
重新运行第1步的场景,开始压测服务器。
3)启动arthas
在命令行下面执行(使用和目标进程一致的用户启动,否则可能attach失败):
java -jar arthas-boot.jar
然后选择要监控的进程,输入1

4)查看dashboard
输入dashboard,按回车,会展示当前进程的信息,按ctrl+c可以中断执行。

图中出现了大量的红色BLOCKED(阻塞)线程,意思是因为竞争某一个资源导致了线程阻塞,压力肯定上不去呀,非常清晰。
6、定位瓶颈
通过thread命令来获取到BLOCKED状态的线程栈信息。
命令行输入:thread 70

简单解读一下,线程栈展示的是代码的调用链,执行顺序是自底向上去看。最后执行的方法是:
com.redmoon.oa.db.SequenceManager.nextUniqueID(127行),
在这个方法中需要获取一把锁才可以继续执行,而这把锁正在被[http-nio-8080-exec-34]这个线程锁持有。接下来就要看34号这个线程正在做什么,为什么持有这把锁不释放。
命令行输入:thread 89

发现这个线程持有这把锁,没干活却在睡觉,接下来反编译或者直接找开发看源码,弄明白这个方法具体在做什么,瓶颈一目了然。发现瓶颈的源码的样子给大家看一下:

当然,这样的瓶颈定位直接使用jstack也是完全可以做到的,只是arthas的功能更强大而已,课堂上结合更复杂的例子用的更多些。
先到这里,下篇见。
