在线服务内存使用率涨到100%如何排查?

上周我们的在线服务程序忽然开始出现内存异常现象,程序的内存会在某个时刻起突然上涨,内存使用率一直涨到100%。我们做了几项针对性的排查:检查程序最近上线内容、使用问题机器的请求日志进行线下反演、登录异常机器查看gstack等,均未能找到问题原因。

周五晚上和周六早上问题开始变得很严重,有几十台机器频繁出现内存异常告警,虽然这些机器在内存使用率上涨到100%后,程序过段时间会自动重启,但还是很影响在线服务的稳定性。于是我们开始通过v*n登录公司内网,周末在家深入排查问题。

我们在机器监控平台查看有问题机器的内存变化曲线,发现正常情况下这台机器内存非常平稳,几乎是一条水平线,但是从某一时刻起内存开始突然上涨,并以稳定速率上涨,约一小时后内存达到100%,示意图如下:

在线服务内存使用率涨到100%如何排查?

我们的老大经验丰富,他注意到CPU和内存同时上涨,当即推测是程序的某个线程进入死循环,不停的分配内存导致。我们的机器CPU是16核,一个核被打满占比约为6%(1/16×100%),这与CPU曲线变化非常吻合。

接下来,我们找到一个内存使用率上涨到100%,还没有被自动重启的机器,远程登录到这台机器,通过执行"top -H -p 程序PID"命令查看具体是哪个线程占用cpu最高,找到其线程号。top默认是按各线程的CPU使用率排序,top内容示意图如下:

在线服务内存使用率涨到100%如何排查?

找到线程号以后,通过执行"gstack 程序PID"命令查看程序各线程的堆栈信息,可以通过"gstack 程序PID > gstack.log"将gstack信息重定向输出到文件中,以方便查看。通过线程堆栈信息可以缩小排查范围,快速定位问题代码片段,gstack内容示意图如下:

在线服务内存使用率涨到100%如何排查?

小提示:通常需要执行多次gstack命令,多观察几次指定线程号的堆栈信息,才能确定问题代码范围。

 

本来问题到这里就已经接近解决了,想不到我们又遇到新的困难:这段代码是兄弟部门的同事所写,既涉及复杂的业务逻辑,又包含一个轮选算法,我们把代码前前后后过了好几遍,也没有看出问题在哪里。

于是我们开始通过gdb分析问题,这里需要注意的是,"gdb -p 程序PID"会导致程序挂起,无法提供服务,因此对在线服务进行gdb分析是有一定风险的。幸运的是我们的程序虽然非常重要,但是由于业务特性和公司平台技术架构的特点,不会对业务造成太大影响。

gdb进入某个线程的堆栈方法是:先用“t 线程ID”进入某个线程(t是thread的简写),接下来通过“f 堆栈号”进入某个堆栈,查看堆栈信息(f是frame的简写)。

通过gdb我们打印出了用户的请求信息,并在测试环境用请求信息重现了问题现象。排查问题时有一句名言:当能把问题稳定复现时,真相就近在眼前了。不过这时天色已晚,已经是周六晚上了。我们老大组织语音群聊,请兄弟部门的代码作者分析讲解代码,结合gdb设置断点、打印关键变量等手段,终于快速定位到问题原因:轮选算法忽略了一个特殊的边界条件,算法无法正常结束,从而出现死循环。

接下来的事情就相对轻松和容易了:修复、CodeReview、验证和上线,大家终于都松了一口气,只是要辛苦运维同学周末操作上线了。

 

总结

分析问题时,仔细观察问题现象很重要,一定要抓住关键信息、明显特征,缩小排查范围。

工程师要熟练掌握gdb、gstack等工具,单纯靠看代码来分析和解决问题是非常困难的。

我们要向经验丰富的人学习解决问题的思路和方法,勤于学习和思考,积累宝贵经验。

整个事情的经过就是这样了。出现问题时还是要以最快速度响应,深入分析。之前由于内存使用率100%程序会被杀掉重启,我们收到报警时没有第一时间去排查,从而错失良机;虽然我们前期努力方向没有跑偏:排查上线记录、利用请求日志企图复现问题、gstack分析等,但是解决问题的决心不足,投入时间有限,导致多次浅尝辄止,最后等到问题大规模爆发才深入排查,其实是很狼狈的。

这跟很多事情是一样的道理,问题很小的时候就应积极介入,防止小问题演化成为大问题,比如在子女教育、做事态度、人际关系等各方面。

最后,解释下为什么我们用线上问题机器的请求日志未能在测试环境复现问题的原因:我们的在线服务落请求日志的时机不对,目前是在请求结束返回结果时才落请求日志,而不是在收到请求的时候落日志。而本次内存使用率上涨到100%的问题是由于某个请求导致单个线程死循环造成的,程序走不到落日志那一步。改进思路是在收到请求时,应先把请求日志记下来,以方便今后的问题排查。

金句分享

当我看迈克尔-乔丹打球,看魔术师约翰逊或者哈基姆-奥拉朱旺打球,我不只满足于看他们风驰电掣。我想把这一刻放慢重温反复回看,直到我搞明白他们到底是怎么做到的。他们是在什么时机启动的?出手的角度是什么?防守球员还能在哪方面做得更好从而来阻止他们得分?这是一个长期的去发现问题改善自己的过程。我想正是这种持续不断的求知欲把我从其他球员中区分开来。

你和其他NBA球员的不同之处在哪?科比的回答。节选自虎扑NBA。

解读:针对性的学习和思考,长期坚持下去,才能让一个人变强。

在线服务内存使用率涨到100%如何排查?

在线服务内存使用率涨到100%如何排查?