做JAVA开发的同学一定遇到过的爆表问题,看这里解决

2023-11-11

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

本文由净地发表于云+社区专栏

记一次Java线上服务器CPU过载问题的排查过程,详解排查过程中用到的Java性能监测工具:jvisualvm、jstack、jstat、jmap。

背景:Java线上服务运行一周后,某个周六晚上CPU使用率突然持续99%,Java进程处于假死状态,不响应请求。秉着先恢复服务再排查问题的原则,在我连接VPN采用重启大法后,CPU使用率恢复正常,服务也正常响应了,如下图一所示:

img(图一)CPU使用率图

但是,当晚的并发量也没有比平时高出许多,为什么会突然出现这种CPU爆表的情况?带着这个疑问,我走上了问题排查的道路。

首先,我查了相关的错误日志,发现故障的时间段内有大量的ckv请求超时,但请求超时并不是ckv server的问题,而是ckv client的请求并没有发出去。那么,为什么ckv client的请求没有发出去呢?日志并没有提供更多的信息给我。

于是,我在Java服务上开启了JMX,本地采用jvisualvm来观察Java进程运行时的堆栈内存、线程使用情况。JMX(Java Management Extensions,即Java管理扩展)是Java平台上为应用程序、设备、系统等植入管理功能的框架;jvisualvm是JDK内置的性能分析工具,位于JDK根目录的bin文件夹下面,它可以通过JMX从Java程序获取运行时的实时数据,从而进行动态的性能分析,如图二所示:

img(图二)jvisualvm

通过观察Heap内存的使用情况,发现其是缓慢增加的,每隔一小段时间被GC回收,图形呈锯齿状,似乎没有什么问题;Threads也没有存在死锁的问题,线程运行良好;在Sampler查看Thread CPU Time的时候发现,log4j的异步日志线程占用的CPU时间是最多的。于是,初步怀疑这是log4j的锅。接着,我对项目代码进行了review,发现某些接口打印了大量的无用日志,日志级别使用也不规范。最后,我对项目的日志进行了整体的梳理,优化后发布上线,并继续观察。

我本以为问题已经解决了。然而,几天后又出现了CPU爆表的情况,这时,我才发现自己错怪了log4j。与上次爆表的情况不同,这次我在公司(表示很淡定),于是我机智地保留了一台机器来做观察,其他机器做重启处理。现在,要开始我的表演了,具体如下:

(1)登陆机器,用 top 命令查看进程资源占用情况。不出所料,Java进程把CPU撑爆了,如下图三所示:

img(图三)进程资源占用情况

(2)Java进程把CPU都占用完了,那么具体是进程内的哪些线程占用的呢?于是,我用了 top -H -p6902 (6902是Java进程的PID)命令找出了具体的线程资源占用情况,如下图四所示:

img(图四)Java线程资源占用情况

图四中的PID为Java线程的id,可以看到id为6904、6905、6906、6907这四个线程基本把CPU资源全部吃完了。

(3)现在,我们已经拿到耗尽CPU资源的线程id了。这时,我们就可以使用jstack来查找这些id对应的具体线程堆栈信息了。jstack是JDK内置的堆栈跟踪工具,位于JDK根目录的bin文件夹下面,可用于打印的Java堆栈信息。我用命令 jstack 6902 > jstack.txt (6902是Java进程的PID)打印出了Java进程的堆栈信息放到jstack.txt文件了;由于堆栈打印的线程的native id是十六机制的,所以,我把十进制的线程id(6904、6905、6906、6907)转化成十六进制(0x1af8、0x1af9、0x1afa、0x1afb);最后,通过 cat jstack.txt | grep -C 20 0x1af8 命令找到了具体的线程信息,如下图五所示:

img(图五)线程堆栈信息

通过图五可以发现,把CPU占满的线程是GC的线程,Java的垃圾回收把CPU的资源耗尽了。

(4)现在,我们已经定位到是GC的问题了。那么,我们就来看看GC的回收情况,我们可以通过jstat来观察。jstat是JDK内置的JVM检测统计工具,位于JDK根目录的bin文件夹下面,可以对堆内存的使用情况进行实时统计。我使用了命令 jstat -gcutil 6902 2000 10 (6902是Java进程的PID)来观察GC的运行信息,如下图六所示:

img(图六)GC运行信息

通过图六可以知道,E(Eden区)跟O(Old区)的内存已经被耗尽了,FGC(Full GC)的次数高达6989次,FGCT(Full GC Time)的时间高达36453秒,即平均每次FGC的时间为:36453/6989 ≈ 5.21秒。也就是说,Java进程都把时间花在GC上了,所以就没有时间来处理其他事情。

(5)GC出现图六的这种情况,基本可以确认是在程序中存在内存泄露的问题。那么,如何确定是哪些代码导致的这个问题呢?这时候,我们就可以使用jmap查看Java的内存占用信息。jmap是JDK内置的内存映射工具,位于JDK根目录的bin文件夹下面,可用于获取java进程的内存映射信息。通过命令 jmap -histo 6902 (6902是Java进程的PID)打印出了Java的内存占用信息,如下图七所示:

img(图七)Java内存占用信息

由图七可以得到,占用内存资源的TOP10类([C 是指char[],String类内部使用char[]来保存数据)的名称、实例数以及占用内存大小(单位:byte),于是问题排查就变得非常简单了。最后,通过review代码确定了问题所在:

  1. 部分接口使用到了L5QOSPacket这个L5的工具类没有做单例,每次请求接口都会生成一个新的实例,浪费了大量的内存。
  2. 代码里边用到的一个第三方提供的QcClient客户端存在内存泄露问题,代码中不恰当地new了大量的对象,而且对存储在ConcurrentHashMap的数据没有做清除清理,从而导致数据一直累计,内存占用持续增加。

解决以上两个问题后,Heap内存的占用维持在2.5G左右,已经没有持续增长的迹象了,业务已正常运行。

以上就是我排查问题的整个过程,以及在这个过程中用到的一些Java性能监测工具。除了本文提及的jvisualvm、jstack、jstat、jmap这些工具,在JDK根目录的bin文件夹下面还有其他许多非常有用的工具,例如:使用 jinfo 查看Java进程相关信息,感兴趣的童鞋可以去研究下。

相关阅读
WCF系列教程之WCF服务配置
php异步执行
黑客用Python:检测并绕过Web应用程序防火墙
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

此文已由作者授权腾讯云+社区发布,更多原文请点击

搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

海量技术实践经验,尽在云加社区

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

做JAVA开发的同学一定遇到过的爆表问题,看这里解决 的相关文章

随机推荐

  • Mac的idea启动项目贼慢,但其它小伙伴启动却很快

    前言 最近开发一直觉自己的mac本idea启动项目贼慢 很影响工作效率 然而同事的mac本启动同一项目却贼快 而且我的电脑性能比他的高 这就很尴尬 然后我尝试了多个方法 终于解决了这个问题 解决办法如下 找到 系统偏好设置 打开后 找到 共
  • 打印螺旋矩阵(C语言)

    本博文主要给大家介绍的是正方形的螺旋矩阵 因为这个螺旋矩阵是最简单的 我之后再把其他类型的螺旋矩阵写成博客和大家一起交流 百度对螺旋矩阵的定义如下 螺旋矩阵是指一个呈螺旋状的矩阵 它的数字由第一行开始到右边不断变大 向下变大 向左变大 向上
  • 2018年度区块链十大安全事件

    2019年1月3日是一个特别的日子 全球的区块链从业者都在以 比特币十年 的特殊仪式 纪念比特币创世区块诞生十周年 十年风雨不由人 十年踪迹十年心 如果说过去七年 这是条少有人走的路的话 过去三年尤其是刚刚过去的2018年 这条路街景开始变
  • for循环嵌套

    写if语句的时候 if else等是可以重叠的 也可以在大的if语句里套一个小的if语句 实际上for循环也是可以嵌套的 例1 写一个脚本输出三行 每行有5个 for i 1 5 fprintf end fprintf n 第一行的5个 输
  • 微信小程序-模板消息全面解析加实例

    一 模板消息是什么 模板消息是微信为小程序提供的消息推送能力 小程序可以向用户发送重要的消息通知 类似于App的推送通知 二 限制 相对于App的推送通知 模板消息有很多限制 这是因为微信放置开发者滥用推送能力骚扰用户 限制1 固定格式 模
  • 【满分】【华为OD机试真题2023 JS】机器人活动区域

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 机器人活动区域 知识点深搜广搜 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 现有一个机器人 可放置于 M N的网格中任意位置 每个网格包含一个非负整数编号 当
  • 【Node.js】定时任务cron:

    文章目录 一 文档 Nodejs 插件 二 安装与使用 1 安装 2 使用 三 cron表达式 秒数 分钟 小时 日期 月份 星期 年份 可为空 四 案例 一 文档 说明文档 https www npmjs com package cron
  • Allegro学习笔记---3.页面设置

    1 参数设置 板层颜色设置
  • YYF login功能

    Controller package com chinasofti fwgl ctrl import java util HashMap import java util List import org springframework be
  • sql怎么把查询的几个结果求和_sql多表查询-从1到很多怎么玩

    大纲 表的加法 表的联结 联结应用案例 case表达式 一 表的加法 加法 union 不保留重复行 select 课程号 课程名称 from course union select 课程号 课程名称 from course1 保留重复行
  • 基于深度学习的图像检索 image retrieval based on deep learning (code ,代码)

    本次代码分享主要是用的caffe框架 至于caffe框架的安装过程不再说明 代码修改自 cross weights 的一篇2016年的文章 但是名字忘记了 谁记得 提醒我下 一 环境要求 1 python 2 gcc 3 opencv 4
  • python随机生成一个数字_如何实现python随机生成数字?

    今天小编就生成随机数 整理了多个方式 方便大家在项目时 根据自己的需求 直接拿来套用即可 以下内容相当详细 具体来看看吧 说明 python中生成随机数主要用到random模块 方法主要包括 randint uniform random s
  • STM32中的BOOT功能

    一 三种BOOT模式介绍 所谓启动 一般来说就是指我们下好程序后 重启芯片时 SYSCLK的第4个上升沿 BOOT引脚的值将被锁存 用户可以通过设置BOOT1和BOOT0引脚的状态 来选择在复位后的启动模式 Main Flash memor
  • python + appium遇到的版本不匹配问题selenium.common.exceptions.WebDriverException: Message: Parameters were inc

    问题 selenium common exceptions WebDriverException Message Parameters were incorrect We wanted required desiredCapabilitie
  • 获取对方IP地址和获取目标MAC地址的方法

    获取对方IP地址的方法 1 直接知道对方的IP地址 2 通过域名获取对方的IP地址 本质上还是直接通过IP进行访问 因为通过域名访问时 需要在DNS服务器中查找域名对应的IP地址 知道对方IP地址后 然后才能访问 DNS域名解析协议 3 通
  • js生成唯一标识id的几种方法

    在开发中偶尔会遇到需要生成唯一id的时候 比如对数组的任意一项进行多次增删改 这时就需要给每一项添加唯一标识符来加以区分 以下总结了几种生成唯一标识的方法 仅供参考 方法一 说明 生成标准的uuid 且方法最简单 function uuid
  • JS / 常用高阶函数

    map map 方法返回一个新数组 数组中的元素为原始数组元素调用函数处理后的值 map 方法按照原始数组元素顺序依次处理元素 注意 map 不会对空数组进行检测 注意 map 不会改变原始数组 param currentValue 必须
  • 【CEEMDAN-VMD-GRU】完备集合经验模态分解-变分模态分解-门控循环单元预测研究(Python代码实现)​

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 1 1 完备集合经验模态分解原理 1 2 变分 模 态 分 解 1 3 GRU 2 运行结果 3 参考文献
  • 前端开发环境,飞速搭建!

    安装 git ssh 配置 生成 ssh keygen t rsa C you email 添加 ssh add ssh id rsa username email git config global user name username
  • 做JAVA开发的同学一定遇到过的爆表问题,看这里解决

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由净地发表于云 社区专栏 记一次Java线上服务器CPU过载问题的排查过程 详解排查过程中用到的Java性能监测工具 jvisualvm jstack jstat jmap 背景