不积跬步,无以至千里
前些天线上消息转发平台CPU 居高不下,CPU超负荷报警不断,客户方电话不断,并要求给出导致问题的原因。
同事的方式
同事呢主要的怀疑点在ActiveMQ的消费能力上,同事折腾了好几天,对ActiveMQ的消费能力进行参数优化,这其中包括以下几个方面:
- 使用连接池(使用cachePool)
- 采用非事务策略
- 调整预抓取策略
当然这只是采取解决方案的一种,同事对解决问题还有一种暴力手段:
- 删除ActiveMQ中所有堆积的消息
- 重启转发平台程序
这种解决方案,我很不赞同,也不提倡。
进行调整后,项目重新发布部署,观察CPU的使用率,指标显示恢复正常;
这个问看似完美解决,可运行几天后运维团队又发来Ticket,CPU超负荷报警,ActiveMQ堆积了大量消息未处理,查看ActiveMQ日志,日志显示目前还在消费几个小时前的消息(这下可打脸了,前面给客户说我们定位到问题的根源,已经对问题进行了修复)。
我的方式
接手这个问题后,按如下方式最终定位到代码问题,通过对代码逻辑的补充完善,最终解决了这个问题,其实问题的定位并不难,关键问题是现在的有些程序员对完成分配的任务,可以很快的完成(前提是不出现什么问题),但一遇到问题,却不知入何下手,查找问题的根源;也许我这样说有失公允,其他程序员若有异议,请不要对号入座。
1、 首先进入到新能源转发平台,在ActiveMQ消息大量堆积的情况下,使用top指令
-
# top 通过top命令很轻易可以看出 占据CPU 很高的进程是 9199
-
# top -Hp 9199 显示9199这个进程线程运行信息列表,再键入P 线程按CPU使用率排序,可看到一个线程就占用了93%的CPU资源,这时我们可以初步确定这个线程执行的代码有问题。
2、通过jstack指令 保存线程栈信息,并在其中查找导致CPU飙升的线程,并定位程序代码
# jstack 9199 > 9199.txt 把9199 的线程栈信息导出到 9199.txt
换算9237 为16进制为0x2415
-
在9919.txt中找到0x2415这个线程
-
通过线程栈信息找到对应代码
3、通过对代码的通读,发现while循环中,有一分支,在上报数据出现异常时,业务处理返回idx = -1,再执行idx++ = 0 ,这样程序将会在while循环中一直执行下去,造成死循环。
- 通过对代码异常情况的考虑,对代码进行了异常处理,项目在在本地拿到异常报文,进行上报后,转发平台能正常工作,且没有ActiveMQ消息的堆积;之后将修改后的代码发布到生成环境,经过10多天的线上环境检测,CPU超负荷运行的情况,得以解决。
总结:针对这种while循环,一定要小心再小心,同时也提醒我们在考虑问题时,不能只考虑正常情况,也要对异常情况进行考虑,对于这种输入一般情况下是正常数据,而偶尔会有异常数据的问题,也要进行考虑;开发这个分支的同学,未进行异常考量,说明其在思考问题上,考虑不周全,逻辑思维不严谨。而开发完程后,一个问题的出现,又不知如何定位代码问题,想要在几万行代码中,查询问题根源,犹如大海捞针;所以,能完成开发工作任务是你的本质,在遇到问题时能快速定位,才是你的能力。