大量线程没结束导致cpu跑满的排查分析

2 篇文章 0 订阅
1 篇文章 0 订阅
背景

公司新迭代了一个版本, 但是上线没多久,cpu就跑满,导致所有的请求都响应很慢, 大多数请求都超时,甚至有一次OOM。出现这样的情况,以前的负责人就叫运维重启。现在这个项目交给我来负责, 我需要把导致这个现象的原因找出来,并解决掉。

前负责人说怀疑是首页接口的问题,看了代码,还真是。

吐槽

公司使用docker运行spring boot项目, docker运行的系统和jdk是非常干净的

linux: Alpine Linux 3.4
jdk: openjdk version "1.8.0_111-internal" (build 1.8.0_111-internal-alpine-r0-b14)

这个版本的linux有些命令是执行不了的,这个版本的jdk同样也没有jps jstack等命令。

要求运维在测试环境给换套系统

linux: CentOS release 6.7 (Final)
jdk: openjdk version "1.8.0_91" (build 1.8.0_91-b14)

OK, 到此,准备工作做好了。

分析

这里写图片描述

在方法中新建了一个线程池,并且在方法中没有关闭。这样会导致每个请求都会创建一个线程池,然后创建几个线程,运行完了后,线程就会处于等待状态,GC回收不了。这是一个很严重的BUG!!!

接下来压测,并使用jprofiler监测JVM运行状况, 拿到结果。

这里写图片描述

等待中心的线程达到了15679个,其它状态的线程都不够其零头。

其中有一个线程一直在耗CPU。另外说下,测试服务器是一个2核的cpu,但是只有一个核是跑满的, 这说cpu的利用率不均匀(有些cpu很忙,有些cpu并不是),这表明只有一条线程在努力的跑。
如果是多核cpu出现利用率不均匀的情况,那说明大多数计算工作都是由一小组线程完成的,应用程序并没有利用其它的处理器。通常有这几种原因:I/O密集、外部限制、锁竟争。

回到主话题,在docker运行的linux中使用命令找到jvm的pid,然后使用top -H -p {pid}找出耗cpu的线程。或者使用ps -mp {pid} -o THREAD,tid,time|sort -k1 -nr|head -15命令也可以。

打到jvm的pid为6

top -H -p 6

这里写图片描述

ps -mp 6 -o THREAD,tid,time|sort -k1 -nr|head -15

这里写图片描述

发现在耗cpu的线程id为25.

先使用jstack把线程的堆栈信息统计到文件中

jstack 6 >data.txt

运行命令将10进制转换为16进制

printf "0x%x\n" 25

输出 0x19

在data.txt中找到nid=0x19的线程。

这里写图片描述

也可以使用如下命令
jstack 6 | grep nid=0x19 -A 30
这行命令会找到nid=0x19的行,并将其下30输出打印出来

发现是metrics监控的线程,根据上面的运行栈去找

这里写图片描述

这里写图片描述

这里写图片描述

发现metrics有一个定时任务,是检查线程状态的,一万五千多个线程,六个状态,就是循环将近十万次 隔60秒循环一次,确实是很耗cpu了。

问题定位到,找到原因,将线程池从方法中移出来,放到类变量中, 初步解决。

这里写图片描述

思考

首页竟然没用缓存,这是** !
后面还要对首页进行优化,使用缓存和管理缓存,不从库里取,不用线程池。

链接

java-jvm-cpu (cpu)高问题排查
如何定位占用cpu过高的线程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值