记一次线上排障——内存爆满、频繁GC、CPU 100%

一. 本文简介

1.1 线上故事 —— 线上内存爆满、频繁GC、CPU 100% ,节点频繁重启

1.2 故障定位排查

1.3 经验反思(看官若是着急,可直接看这里)

二. 线上故事与排查

2.1 线上故事

    与以往发布项目流程一样,上午项目A开始由运维灰度发布(a,b集群8节点)。部署日志如下:

部署流程看上去一切正常,节点部署与验证均通过。看样子,这次上线应该没啥问题,可以安心吃个午饭,下午再新业务验证。然而......

在b集群还在继续部署,流量全部打在已部署完成的a集群时(即a集群4个节点承担了100%流量),线上告警触发,a集群开始有节点自动重启。赶紧去看项目的日志明细。一场在线定位故障的大幕拉开。

2.2 线上故障排查

  日志查看系统graylog显示最近5分钟,error 日志不到10条,大部分error内容为获取数据库连接异常:

说实话,当时看到这个异常时,心里还不是很慌(好歹不是业务代码异常,要是出现NPE,那要挨板子~)。然而......

当看到这种数据库连接获取不到时,心想着,部署赶上业务高峰期啦? 走你,去grafana看项目指标监控去。

节点http请求统计图:

业务接口调用topN 统计图

看上去,11点后部署的时候,业务请求量确实不算小,难道是刚巧a,b集群灰度部署的时候,一半的4个节点没抗住100%流量,有请求在获取数据库连接这里堆积并超时引发error,并进一步触发了节点健康检查未通过,导致节点重启?

随着健康的节点数渐渐上升,在未见到其他error日志的情况下,本以为一切虚惊一场。但随后健康节点数一直未恢复到初始值8,伴随着重启,数量一直在上下波动。此时,除了收到告警,相关技术工作群里,开始有依赖我们的服务负责人,在询问我们的服务是不是跪了!紧接着,客户端业务线也反馈页面加载缓慢!事情开始变的紧急了(生产无小事,是我们反应慢了,尤其系统重启)。这时候,由于第一步定位问题太粗糙了,未能拍板是发布的代码引起的问题,所以在节点频繁重启且影响上下游服务的时候,我们走了扩容节点而非回滚版本的动作(注意,这一动作有很大的争议,值得商榷)。但是,扩容了一倍来到了16个节点,重启现象并未解决,只是减小了对上下游的影响。这时候,心里预感应该是新上的代码有问题了。在放弃新上业务回滚后,重启现象消失。

继续看grafana监控,异常指标跳入眼帘。

JVM 统计指标

Container 指标

上面JVM和CPU 的监控指标,内容概括下就是:内存突然爆满,GC执行变得频繁,GC耗时来到可怕的秒级,cpu也直接干满了。 这些,才是本次节点重启的原因(打脸啊,一开始居然没看这些指标)。

那,什么引起了这些现象?哪里的代码突然吃了那么多内存?进而引起了GC 和CPU 疯狂干活??

这个时候,review代码,有点力不从心,新上的代码多,涉及开发人员也多。根本上,dump分析才是王道。这里不讨论如何获取和分析dump,使用当前部署环境运维能支持的手段。我们这里使用的是 perfma 集成化dump收集分析软件。在运维准备perfma环境以及后面学习使用的同时,负责跟进排查的人也在梳理上线后的监控指标与相关日志,并check核心代码。

后面我们怀疑了String拼接的两个方法,但一推算,哪怕调用一次申请1k的内存资源,1000qps也才1m,短时间内不可能导致内存骤升。应该是创建了什么大对象。

可能真是当局者迷,亦或者上线触发告警自乱了阵脚。最终,在数据库慢查日志这里,找到了苗头

查询耗时慢不可怕,可怕的是返回的记录数达到了400K+ ... 这就很恐怖了,一条查询就可以轻松吃掉几十上百兆的内存。再一定位代码,是本次新加的查询代码。至此,真相基本浮出水面。不多久,那边的perfma也有了结果:

一个线程就吃掉了440m内存,再观察具体实例属性,对应的实体ToutiaoExposureRecord,没跑了,就是那个慢查。

后面查了下生产的数据库:

业务代码那里,未对生产的idfa 为0000000 做兼容考虑,遂查询引发了后续事故。

代码修正后,部署上线,监控指标一切正常了。

三. 经验反思

3.1 生产出现故障,不能掉以亲心但也不要慌乱!稳住!

3.2 降低故障影响面,降低损失!宁可放弃上线新功能,万不可宕机影响现有业务功能!

3.3 排障注意章法流程,不要东一榔头西一棒子。应用运行log,系统内存、线程、cpu监控等利用起来。以及,注意数据库慢查!!!

 

思考:在本次案例中,部署上线后,出现节点重启,可用健康节点不足一半的情况下,已经严重影响其他业务功能了。此时,节点重启原因还未找到,是选择扩容暂时保系统还是选择回滚版本呢?扩容相当于给了更多节点重启的缓冲时间,以数量换时间;回滚相当于认为问题出在新版本的代码上,但回滚部署,根据这里灰度发布的流量调整规则(见第一张图),会将100%的流量打到一半的节点上,假设此时承受流量的那一半节点已经奄奄一息了,那服务估计就被打爆了!这种场景,也是需要根据实际情况认真考虑斟酌的!

 

评论区欢迎讨论!觉得有用点个赞再走吧。感谢!!!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章