记一次线上Java进程假死问题分析

背景

上午11点左右,监控系统突然发出来一个告警,分布式数据库的某个代理节点(Java编写)连接失败率100%,每次都是超时,赶紧登上后台去查看

问题分析

一、查看系统指标

  1. top命令查看一些基础指标,cpu使用率不高,内存一直都是80%左右,io,网络都没问题
  2. top -Hp Java进程的pid,查看进程内的情况,1786个sleep状态的线程
  3. 赶紧jstack了一份线程信息,发现很多线程都阻塞在了ArrayBlockingQueue的put方法上
  4. 紧接着dump一份内存映像,27个G,心累,还得找台大内存的电脑去分析

二、jstack信息分析

分析之前得先搞清楚一个线程的生命周期
线程生命周期

因为很多线程处于sleep状态,所以优先排查waiting和timed waiting状态的线程,一统计发现有1500多个,随机挑了几个,基本都是阻塞在ArrayBlockingQueue的put方法上,有这些信息就够了,接下来根据jstack里的线程信息ServerExecutor-2-thread-1101,再去分析dump文件
在这里插入图片描述

三、dump文件分析

工具我用的是MAT,还是挺好用的(前提是得有个牛逼的电脑O^O),先上个图,本次分析主要使用的是标黄的地方
在这里插入图片描述

查看线程情况,然后跟据jstack里获取到的线程id过滤一下,再一步步展开线程,看啊可能此线程在做什么,以及卡在哪里,从标黄的地方可以看出,此线程在执行一个batchInsert任务,执行任务之前呢要先记录一条日志,记录日志的动作是异步的,只是写入到一个ArrayBlockingQueue里,但是就是这个写入动作卡住了,查看ArrayBlockingQueue的地353行代码,当队列满了的时候,线程就会进入阻塞等待状态(基础好一点的同学不用翻代码也能猜到了)

在这里插入图片描述
在这里插入图片描述

四、综合分析

上一步分析到日志的队列满了(队列大小为100000),导致写日志操作都阻塞了,为什么写日志的队列会满呢,查看监控该节点并没有很大的并发,并且调整了权重让新的请求不再分发到这个节点之后,队列还是满的,一直持续,不见下降,另外一种可能就是从日志队列里取数据的操作停了,查看从队列里读数据的线程,发现确实停掉了,再结合服务器日志,发现是OOM导致的线程停止

解决方案

既然问题清晰了,解决方案也很简单,给从日志队列里读入据写入磁盘的操作加个try catch,catch Throwable对象,这样可以捕捉到OOM,避免线程因为OOM停止,加try catch的时候范围尽量小

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值