性能剖析是一个低强度分析工具,可以用在生产应用程序中识别瓶颈。
它是在指定时间范围(持续时间)内定时(采样周期)的调用系统中断,然后收集当前的调用栈(call stack trace)信息,记录调用栈中出现的函数及这些函数的调用结构,基于这些信息得到函数的调用关系图及每个函数的 CPU 使用信息。通过这些信息,我们可以清楚的看到时间是花费在哪一个方法的哪一行上,从而有针对性的进行代码的优化。
详细数据介绍:性能剖析相关知识
我们的 Ai 产品中有两种方法可以进行性能剖析的设置,分别是 应用>tier>性能剖析 以及 关键事务>性能剖析。
2. 应用>tier>性能剖析
3. 关键事务>性能剖析
If you want to… | Do this |
---|---|
查看性能剖析对应关键事务信息 | 选择关键事务下对应名称 |
查看性能剖析对应的 tier 应用情况 | 选择应用程序下对应名称 |
从不同的维度查看 trace | 点击耗时/开始时间 |
查看单个 trace 的详细信息 | 点击选中的 trace |
线程分析页面
调用栈信息可以根据需要进行展开和收缩。
此处的百分比是根据在采样周期中,该行代码总计被采样到的次数与总采样次数的百分比。代码后括号中的内容是该代码在事务中的行数。
停到某个类的某个方法比如 get 的方法,一般都是由于在进行密集计算,或者调用数据库但是数据库长时间没有返回结果,或者数据库中有锁。如果是 cpu 慢,就会出现在这里;如果由于锁等原因,就会出现在线程和锁的标签页中。
时间分布图的百分比计算: 该行代码总计被采样到的次数与总采样次数的百分比
CPU 时间图的百分比计算: 该行代码总计在 runable 状态被采样到的次数与总采样次数的百分比。
可以理解是该方法在这类请求中的对于 CPU 开销占比。
线程和锁图的百分比计算:该行代码总计在 norunable 状态被采样到的次数与总采样次数的百分比。 可以理解是该方法在这类请求中的对于处于 blocked 状态时间的占比。
注:如果想要进行 关键事务>性能剖析 则需要预先将要进行性能剖析的 Web 事务设为关键事务,且性能剖析进行时必须确保剖析的探针具有持续的访问。
设置方法如下,
问题调查和分析:
java.lang.classloader.defineclass
动态类加载上,这明显是一个由于过度的动态类加载造成的应用缓慢。
这个问题的后续:
同时结合客户终端请求有大量 502 报错。
初步分析是因为线程池用尽,导致请求堵塞在请求队列中,最后导致大量请求访问超时,报 502 错误。
给出建议操作: 增大线程池最大线程数量,继续观察。
* 第二阶段:
增大线程池最大线程数量以后,高峰期访问性能并没有得到提高,我们需要进一步分析。
由 a1 进一步分析:应用表现出性能的下降,却没有观察到 CPU 占用的提高,那就表示线程可能在等待 I/O 或是其他一些操作的结果。
同时通过 JVM 性能剖析功能,发现确实用户在发起对于后台系统调用以后都会进入 thread.sleep。(时间太久找不到图,就不提供截图了。)
与客户开发确认后发现,在调用交易平台后端的 client.jar 包中每次调用发起以后都会调用 thread.sleep 进行线程休眠(休眠时间与thread数量成正比)。
此时给出的相关建议:线程是一种十分宝贵的资源,创建,销毁,切换 都是相当耗性能的,当 Sleep 的时候,就等于说:现在我不用,但是你也别想用。你要用,自己去 Create 一个。当 create 的线程到底最大值以后,请求就只能阻塞在请求队列中了。因此 sleep 的时候虽然不占用 CPU,但是占着线程资源,会严重阻碍系统的线程调度。
经过现场与客户后台系统开发确认,为了保证前台系统的正常运行,临时取消了 thread.sleep 的调用。同时在客户后台系统加装探针,调整线程池大小,确认后台系统可能的瓶颈。
3.问题类型:应用性能异常缓慢