记一次上线就跪的故障排查案例
这个是我很早以前解决的一个案例,其现象是系统每次上线后,20多台机器,总有两三机器,出现假死的情况。如何判断出系统假死?借助的是一个第三方公司运维监控平台;这种情况,前同事称之为的“假死”,需要重新启动系统才能恢复。因为我是新来乍到,觉得这种情况不正常,而且对研发(在这边是研发上线)来说,是一个非常大的上线负担;于是我决定解决一下这个“百年难题”。
我亲自上线,果然很快就碰到了假死的机器。我看到机器的CPU,内存和磁盘IO都很正常,根本不像出问题的机器。直觉告诉我,先用jstack打印个堆栈看看当前tomcat在做什么吧,于是叫上支持上线的运维小哥给打印了一个,然后手工重新部署了一下有问题的机器(记住出问题一定要先止损)。
拿到手的堆栈,第一眼就发现了一些问题。前几行如下:
可以看到tomcat的线程号已经到了215,而tomcat默认最大处理数为200,已经到了饱和状态。后续的请求就只能排队了。
堆栈中,有很多waiting to lock <0x0000000784588098>的线程,从执行堆栈看,应该是CXF要调用.NET的webservice。调用的业务方法各不相同。
继续往下看,在堆栈的后半部分(注意行数),打印了一个死锁的提示。
我们进一步分析,为了方便大家阅读,我对上面的死锁线程画了一个依赖图,可以看出,线程25和线程48形成了死锁。这4个线程的等待关系如下:
继续分析,什么导致的死锁;
线程25的堆栈如下:
线程48的堆栈:
线程持有锁和堆栈中提示的锁信息正好照应
从上面堆栈可以分析出,gson和第三方的agent发生了循环死锁。至此问题的解决方法已经有了,要不去掉gson,要不就去掉那个第三方agent。
除了上面的解决方法外,我们还在系统中增加了一个容器探活的接口(这个功能从监控来看,非常有意义)。即在controller中写一个方法,直接返回一个字符串。这样在外部定时的去调用接口(也可以手工使用curl来探测),就知道这个服务是否还存活,也不用第三方监控系统来判断了;
经验教训:
1、系统需从容器级别支持外部探测,以证明自身健康
2、不要轻易引入外部agent
知识点:
1、tomcat(BIO)默认最大线程数200
关注我的微信公众号,获取最新故障案例分析;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探