做JAVA开发的同学一定遇到过的爆表问题,看这里解决
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
记一次Java线上服务器CPU过载问题的排查过程,详解排查过程中用到的Java性能监测工具:jvisualvm、jstack、jstat、jmap。
背景:Java线上服务运行一周后,某个周六晚上CPU使用率突然持续99%,Java进程处于假死状态,不响应请求。秉着先恢复服务再排查问题的原则,在我连接VPN采用重启大法后,CPU使用率恢复正常,服务也正常响应了,如下图一所示:
(图一)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程序获取运行时的实时数据,从而进行动态的性能分析,如图二所示:
(图二)jvisualvm
通过观察Heap内存的使用情况,发现其是缓慢增加的,每隔一小段时间被GC回收,图形呈锯齿状,似乎没有什么问题;Threads也没有存在死锁的问题,线程运行良好;在Sampler查看Thread CPU Time的时候发现,log4j的异步日志线程占用的CPU时间是最多的。于是,初步怀疑这是log4j的锅。接着,我对项目代码进行了review,发现某些接口打印了大量的无用日志,日志级别使用也不规范。最后,我对项目的日志进行了整体的梳理,优化后发布上线,并继续观察。
我本以为问题已经解决了。然而,几天后又出现了CPU爆表的情况,这时,我才发现自己错怪了log4j。与上次爆表的情况不同,这次我在公司(表示很淡定),于是我机智地保留了一台机器来做观察,其他机器做重启处理。现在,要开始我的表演了,具体如下:
(1)登陆机器,用 top 命令查看进程资源占用情况。不出所料,Java进程把CPU撑爆了,如下图三所示:
(图三)进程资源占用情况
(2)Java进程把CPU都占用完了,那么具体是进程内的哪些线程占用的呢?于是,我用了 top -H -p6902 (6902是Java进程的PID)命令找出了具体的线程资源占用情况,如下图四所示:
(图四)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 命令找到了具体的线程信息,如下图五所示:
(图五)线程堆栈信息
通过图五可以发现,把CPU占满的线程是GC的线程,Java的垃圾回收把CPU的资源耗尽了。
(4)现在,我们已经定位到是GC的问题了。那么,我们就来看看GC的回收情况,我们可以通过jstat来观察。jstat是JDK内置的JVM检测统计工具,位于JDK根目录的bin文件夹下面,可以对堆内存的使用情况进行实时统计。我使用了命令 jstat -gcutil 6902 2000 10 (6902是Java进程的PID)来观察GC的运行信息,如下图六所示:
(图六)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的内存占用信息,如下图七所示:
(图七)Java内存占用信息
由图七可以得到,占用内存资源的TOP10类([C 是指char[],String类内部使用char[]来保存数据)的名称、实例数以及占用内存大小(单位:byte),于是问题排查就变得非常简单了。最后,通过review代码确定了问题所在:
- 部分接口使用到了L5QOSPacket这个L5的工具类没有做单例,每次请求接口都会生成一个新的实例,浪费了大量的内存。
- 代码里边用到的一个第三方提供的QcClient客户端存在内存泄露问题,代码中不恰当地new了大量的对象,而且对存储在ConcurrentHashMap的数据没有做清除清理,从而导致数据一直累计,内存占用持续增加。
解决以上两个问题后,Heap内存的占用维持在2.5G左右,已经没有持续增长的迹象了,业务已正常运行。
以上就是我排查问题的整个过程,以及在这个过程中用到的一些Java性能监测工具。除了本文提及的jvisualvm、jstack、jstat、jmap这些工具,在JDK根目录的bin文件夹下面还有其他许多非常有用的工具,例如:使用 jinfo 查看Java进程相关信息,感兴趣的童鞋可以去研究下。
相关阅读
WCF系列教程之WCF服务配置
php异步执行
黑客用Python:检测并绕过Web应用程序防火墙
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识
此文已由作者授权腾讯云+社区发布,更多原文请点击
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!
海量技术实践经验,尽在云加社区!
做JAVA开发的同学一定遇到过的爆表问题,看这里解决的更多相关文章
- 大学同学做Java开发比我多5K,八年老Android只会crud该转Java吗?
最近在网上看到这样一个帖子: 做了八年Android开发,感觉这块做着也挺没意思,日常工作就是做一些架构优化,质量数据监控,改一改构建脚本,最主要的是业务负责人没有一个是做客户端的,都是后端的人. 最 ...
- 所有做java开发的都是些垃圾
所有做java开发的都是些垃圾,再垃圾的框架,只要有人用,对java程序员来说那就是高性能,高可用,解耦的,非常优秀的一款框架.属于吃屎都吃的津津有味.java里的框架都是垃圾,连一个不错的都没有.比 ...
- java突破------一撸到底(做Java开发,遇到瓶颈是保持现状还是寻求突破?)
java突破------一撸到底(做Java开发,遇到瓶颈是保持现状还是寻求突破?) 很多人做Java开发2.3年之后,都会觉得自己遇到了瓶颈.什么都会又什么都不会,如何改变困境,为什么很多人写了7. ...
- 使用Eclipse-Maven-git做Java开发(3)--Eclipse的安装和配
使用Eclipse-Maven-git做Java开发(3)--Eclipse的安装和配 https://my.oschina.net/songxinqiang/blog/474530
- 转载:做Java开发这一年 (火龙果软件)
转载:http://www.uml.org.cn/success/201410205.asp 从去年到现在,从.NET转向Java开发(只是因为项目原因,绝对与平台好坏没有关系)差不多有一年的时间了. ...
- 一个老牌程序员说:做Java开发,怎么可以不会这 20 种类库和 API
- 为什么做java开发的公司需要那么多程序员?
注:文章转载自知乎 透过现象看本质. Java是企业应用市场的王者,如果一家非互联网公司用Java,那么十有八九是做企业应用的. 所以,这个问题本质上是:为什么做企业应用的公司需要那么多Java程序员 ...
- 这份SpringMVC执行原理笔记,建议做java开发的好好看看,总结的很详细!
什么是SpringMVC? Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供的web模块,包含了开发Web 应用程 ...
- 做Java开发7年,今年9个月时间圆梦饿了么P7
前言 工作拧螺丝,面试造火箭.我想这是每个程序员比较头疼的事情吧!但是,又必须要经历一个面试流程,尤其是摸不清面试官问的问题,导致面试的时候不知道如何回答.本文是工作7年Java程序员从几十次面试中挑 ...
随机推荐
- selenium 3.0变化
Selenium3.0的变化 最大的变化应该是去掉了Selenium RC 了,这是必然的结果.Selenium RC 是Selenium1.0的产物,Selenium2.0以WebDriver为主, ...
- Win10系统进行远程桌面连接出现身份验证错误怎么办
在win10系统中,自带有远程桌面连接功能,但是有时候会遇到一些问题,比如有不少用户反映说在进行远程桌面连接的时候,出现身份验证错误的情况,导致远程连接失败,接下来给大家分享一下Win10系统进行远程 ...
- html语义化练习易牛课堂代码
html <body> <header> <!-- 导航 --> <nav> <a href=" ...
- Git的操作方法
创建仓库 git clone 加上你的远程仓库克隆下来 git add . 把你文件里面的改动更改添加到git里面 git status 查看状态,更新了那些内容 git commit -m" ...
- 关于php条形码生成(barcode),修改样式
今天听错了需求,以为要重新设计条形码,第一次制作这个,经过搜索使用的barcode这个第三方的,具体使用步骤网上很多就不在这里详细介绍了.主要是今天遇到的样式修改问题: barcode经过查看是无法自 ...
- 49-2015年第6届蓝桥杯Java B组
1.三角形面积 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字. image.png 计算方法: 8 * ...
- Linux-目录结构及文件系统
1.Linux 系统的顶层目录结构 / 根目录 ├── bin 存放用户二进制文件 ├── boot 存放内核引导配置文件 ├── dev 存放设备文件 ...
- 使用U盘安装CentOS7
为了在公司的旧笔记本电脑上安装centos供自己学习使用折腾了两天,终于在看了https://www.cnblogs.com/yeeo1/p/7306611.html这篇博文后装上了, 以下内容为转载 ...
- react 子元素修改父元素值的一个偏方,虽然简单,但是不建议用,
this.state.obj = { name: "小明" } <Zizujian obj={this.state.obj} /> // 子组件这样修改父元素的值 // ...
- 最短路径(SP)问题相关算法与模板
相关概念: 有向图.无向图:有向图的边是双行道,无向图的边是单行道.在处理无向图时,可以把一条无向边看做方向相反的两条有向边. 圈 cycle / 回路 circuit:在相同顶点上开始并结束且长度大 ...