关于 Load飙高、RT 增大、CPU飙高等问题,我们在线上问题排查的分类中有单独介绍过如何排查。那么为什么单独又写一篇呢?
一方面是这个问题确实比较典型的,而且也很场景,另外就是这个问题有的时候比较难定位,因为可能还没等定位到,就恢复了。
那么,我们该如何定位这些问题呢,他们可能有哪些原因呢?我们先分析原因的可行。
因为这个问题的前提是应用启动后的前几分钟,那么就分析前几分钟有啥不一样就行了。
Load 和 CPU 的飙高,说明当前 CPU 比较忙,意味着有很多事在处理,以及有很多任务在排队等待被处理。
而 Load 和 CPU 的飙高就会导致 RT 的增大,因为 CPU 没资源处理你的响应了,那么你的 RT 就变大了呗。
所以,其实这个问题啊,本质上还是在 CPU 上面,那么启动过程中,有啥情况会导致 CPU 比较忙呢?
情况一、机器不够:
首先,有一个比较常见,但是也很容易被忽略的问题,那就是应用发布过程,很多公司都是金丝雀发布,或者叫滚动发布,意味着发布过程中对外提供服务的机器数会减少。比如100台机器,你分10批发布,那么线上同时存活的机器就只有90台,那么就意味着这90台要处理平时100台机器的请求量。
那么就有一种可能是因为请求量大,机器数少,导致负载变高,进而导致 RT 变长,这个问题的现象是RT变长或者CPU 飙高一般会伴随整个发布过程,一旦发布完成了,就恢复了。这种情况的话你只需要延长一个批次的发布时间,就能明显的观察到整体的有问题的时长变长了,这时候如果你试着扩容几台机器上去,问题就会有所缓解。
所以说,这个问题的解决也很简单,那就是扩容,或者发布前扩容,发布后再缩容即可。
情况二、存在初始化任务
有些应用,在启动过程中有很多东西需要初始化,比如从配置中心拉配置、从注册中心拉配置、从文件中拉配置、从数据库预加载资源做缓存预热等等。
还有一些,比如说连接池的创建初始化、线程池的创建初始化等等,定时任务的执行等等,都差不多是类似的过程。
这一类过程都可以归结为启动的预热过程,而这些预热过程需要网络交互、需要内存操作那么就会对机器资源造成一定的消耗,那么就可能会出现接口响应慢,RT 变长的情况。
这个问题也比较好排查,那就是在应用启动过程,查看你的活跃线程数,以及占用 CPU 比较高的一些线程,看看他们是不是一些后台任务,或者是预热任务。
具体可以用 jstack 或者是 arthas 工具都能看
这个问题解决也好解决,那就是修改一下你的启动脚本,让你的应用在完成预热之后再把服务暴露出去,再放流量进来。这里面还涉及到一些优雅上下线的问题,这里不做展开了,文档左上角搜索搜一下就有了。
情况三、JIT 优化
这个是一个比较典型的案例,比如下面这个案例,就是我们真实生产环境遇到的一个:
这个问题和 JIT 优化有关在哪里呢?
两种情况,情况一是在 JIT 优化完成前, 代码需要解释执行,这个过程本来就不如编译执行快,那么就可能看上去 RT 要比平时高一些。当然这个影响比较小。
还有一个更重要的情况,那就是应用刚刚启动后,JIT 优化会开始介入,这时候会做频繁的热点代码检测以及代码编译的处理,就会耗费很多 CPU 资源,导致 Load、CPU 比较高、进而导致 RT 变高。
这个问题的解决思路在上面的链接中提到了,就是要么做流量预热,要么就是提升JIT优化的效率,要么就是降低瞬时请求量,不重复写了,上面的文章进去看一下即可。
一般来说主要是以上这个三个问题,当然,事无绝对,可能还有一些其他的原因,比如说网络连接的初始化建立、Servless 应用的冷启动等等,在下面这篇兄弟文章中介绍了一下,可以作为扩展学习: