今天测试团队反馈说,服务A的响应很慢,我在想,测试环境也会慢?于是我自己用postman请求了一下接口,真的很慢,竟然要2s左右,正常就50ms左右的。

于是去测试服务器看了一下,发现服务器负载很高,并且该服务A占了很高的cpu。先用top命令,看了load average,发现都到了1.5左右(双核cpu)了,并且有一个java进程(20798)占用cpu一直很高,如下图:

于是,用命令jps -l看了一下java的20798,刚好就是服务A。

究竟服务A在跑什么,毕竟是测试环境。于是使用top -Hp 20798看一下是哪个线程在跑,如下图:

发现线程20840占用cpu非常高,其他几乎都是0。通过以下命令输出该线程id(20840)的16进制:

printf "%x\n" 20840

  

输出如下:

线程id(20840)的16进制是5186。

然后使用以下命令打印出该线程的堆栈信息:

jstack -l 20798 | grep -A 20 5168

  

输入如下:

发现占用cpu的进程是jvm的GC线程,于是猜测是不是由于一直在进行FGC导致cpu飙高,于是使用以下命令看下FGC的频率和耗时:

jstat -gc 20798 1000

  

输出如下:

发现,果然是不断地在进行着FGC,并且每次FGC的时间一直在升高。是什么导致一直都在FGC呢?是有大对象一直在创建,回收不了?于是使用以下命令看下heap中的对象情况:

jmap -histo:live 20798 | head -20

  

输出如下:

发现一个业务类对象竟然有150w+个,并且占用了264M的堆大小,什么情况,并且这150w+个对象还是存活的(注意jmap使用的时候,已经带上了:live选项,只输出存活的对象),吓我一跳。于是赶紧使用以下命令打出线程堆栈来看一下:

jstack -l 20798 > jstack_tmp.txt

  

输出如下:

然后使用如下命令在输出的线程堆栈中根据对象类查找一下:

grep -C 30 'omments' jstack_tmp.txt

  

输出如下:

猜测是由于一下次从db load出了太多的CommentsEntity。

于是使用以下命令dump出heapdump出来重复确认一下:

jmap -dump:live,format=b,file=news_busy_live.hprof 20798

  

把heapdump文件news_busy_live.hprof下载到windows本地,使用mat工具进行分析,第一次打开发现打不开,毕竟news_busy_live.hprof有3G那么大,mat直接报OOM打不开,发现mat的配置文件MemoryAnalyzer.ini里面的配置-Xmx1024m,heap size才1G,太小了,于是改成-Xmx4096m,保存,重新打开mat,再打开news_busy_live.hprof文件即可,如下图:

发现mat已经帮我们分析出了内存泄漏的可以对象,233w+个对象(前面通过jmap命令输出的150W+个,是后面为了写文章而专门重现的操作,这里的233w+个是当时真的出问题的时候dump出来的heap dump文件),太恐怖了。

通过以下操作,查看

点击exclude all ....,因为弱引用,软引用,虚引用等都可以被GC回收的,所以exclude,输出如下:

发现一共有6个线程引用了那233w+个对象,于是去前面dump出来的线程堆栈跟踪以下这几个线程的情况,发现堆栈里面刚好这几个线程也是在处理comments相关的逻辑,这个是刚好碰巧,一般线程id都对不上的,毕竟线程处理完之后就释放了的。所以我们还是看回前面线程堆栈的信息,这里贴出根据关键字"omment"搜索出来的线程堆栈的信息,如下:

"XNIO-5 task-77" #248 prio=5 os_prio=0 tid=0x00007fc4511be800 nid=0x8f7 runnable [0x00007fc3e5af2000]   java.lang.Thread.State: RUNNABLE       ...        at cn.xxxxxx.news.commons.redis.RedisUtil.setZSet(RedisUtil.java:1080)        at cn.xxxxxx.news.service.impl.CommentsServiceV2Impl.setCommentIntoRedis(CommentsServiceV2Impl.java:1605)        at cn.xxxxxx.news.service.impl.CommentsServiceV2Impl.loadCommentsFromDB(CommentsServiceV2Impl.java:386)        ...        at cn.xxxxxx.xxxs.controller.vxxx.xxxxController.getxxxxxx(NewsContentController.java:404)        at cn.xxxxxx.xxx.controller.vxxx.xxxxxController$$FastClassBySpringCGLIB$$e7968481.invoke(<generated>)        ...        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)        at java.lang.Thread.run(Thread.java:745)​   Locked ownable synchronizers:        - <0x00000000f671ecd0> (a java.util.concurrent.ThreadPoolExecutor$Worker)​

  

    

从上面的堆栈信息,结合前面的猜测(猜测是一次性从db load出太多的CommentsEntity),猜测应该是函数loadCommentsFromDB一次性从db load出太多CommentsEntity了。于是看了一下业务代码,发现load出来的commentsEntity会放到redis的某一个zset,于是使用redis destopmanger看一下这个zset的数据,发现这个zset有22w的数据,从中找出几条,发现对应的newsPk都是同一个,根据newsPk在db中找一下该newsPk的comments总记录,发现该newsPk的comments记录数是38w+条,那就是这个问题了,一次性从db中load了38w+的数据到内存。

一次性load那么多数据到内存,这肯定是一个慢查询,不管是db还是网络io,都肯定很慢。然后发现业务代码还会有一个for循环,把这个CommentsEntityList遍历一遍,一条一条放到redis,这也是一个非常慢的过程。

然后我去看了服务A的access log,发现在短时间内,请求了该newsPk多次数据,所以就导致了jvm的heap空间不够,然后出现不断FGC的现象,并且该newsPk的请求,由于超时,都在网关超时返回了。

为了验证这个问题,我把相关的redis缓存删除,然后调用该newsPk的接口获取数据,发现很慢,并且cpu立刻飚上去了,然后调多几次,并且不断地进行FGC,至此已经复现了该问题,和猜测的一样。等数据load到redis之后,再访问该接口,就很正常没问题。

上面发现问题的代码,找时间做一下优化才行,先重启服务A,让服务可用先。

                    欢迎关注微信公众号“ismallboy”,请扫码并关注以下公众号,并在公众号下面回复“FGC”,获得本文最新内容。

 

一次FGC导致CPU飙高的排查过程的更多相关文章

  1. STORM在线业务实践-集群空闲CPU飙高问题排查

    源:http://daiwa.ninja/index.php/2015/07/18/storm-cpu-overload/ 2015-07-18AUTHORDAIWA STORM在线业务实践-集群空闲 ...

  2. 记一次yarn导致cpu飙高的异常排查经历

    yarn就先不介绍了,这次排坑经历还是有收获的,从日志到堆栈信息再到源码,很有意思,下面听我说 问题描述: 集群一台NodeManager的cpu负载飙高. 进程还在但是看日志已经不再向Resourc ...

  3. 生产系统CPU飙高问题排查

    现状 生产系统CPU占用过高,并且进行了报警 排查方法 执行top命令,查看是那个进程导致的,可以确定是pid为22168的java应用导致的 执行top -Hp命令,查看这个进程的那个线程导致cpu ...

  4. STORM在线业务实践-集群空闲CPU飙高问题排查(转)

    最近将公司的在线业务迁移到Storm集群上,上线后遇到低峰期CPU耗费严重的情况.在解决问题的过程中深入了解了storm的内部实现原理,并且解决了一个storm0.9-0.10版本一直存在的严重bug ...

  5. 记一次JAVA进程导致Kubernetes节点CPU飙高的排查与解决

    一.发现问题 在一次系统上线后,我们发现某几个节点在长时间运行后会出现CPU持续飙升的问题,导致的结果就是Kubernetes集群的这个节点会把所在的Pod进行驱逐(调度):如果调度到同样问题的节点上 ...

  6. mongoDB cpu飙高问题

    问题描述: 最近几天生产环境上的mongodb一直在报警,cpu飙高,其他如内存.iops.连接数.磁盘操作等都正常.通过定位业务,发现是由于mongodb的表其中一个查询未建立索引导致,110多W的 ...

  7. 你要偷偷学会排查线上CPU飙高的问题,然后惊艳所有人!

    GitHub 20k Star 的Java工程师成神之路,不来了解一下吗! GitHub 20k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 20k Star 的Java工 ...

  8. 【面试普通人VS高手系列】CPU飙高系统反应慢怎么排查?

    面试过程中,场景类的问题更容易检测出一个开发人员的基本能力. 这不,一个小伙伴去阿里面试,第一面就遇到了关于"CPU飙高系统反应慢怎么排查"的问题? 对于这个问题,我们来看看普通人 ...

  9. 系统CPU飙高,怎么排查?

    cpu是整个电脑的核心计算资源,对于一个应用进程来说,cpu的最小执行单元是线程. 导致cpu飙高的原因有几个方面: cpu上下文切换过多,对于cpu来说,同一时刻下每个cpu核心只能运行一个线程,如 ...

随机推荐

  1. leetCode刷题 | 两数之和

    两数之和: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数 ...

  2. 【x64软路由】OpenWrt(LEDE) 20200329编译 反追踪 抗污染 加速 PSW 无缝集成 UPnP NAS

    固件说明 基于Lede OpenWrt R2020.3.19版本(源码更新截止20200329)Lienol Feed及若干自行维护的软件包 结合家庭x86软路由场景需要定制 按照家庭应用场景对固件及 ...

  3. Spring 循环引用(三)源码深入分析版

    @ 目录 前言 正文 分析 doGetBean 为什么Prototype不可以 createBean doCreateBean getEarlyBeanReference getSingleton b ...

  4. 【华为云技术分享】智能诊断和优化,华为云DAS服务云DBA平台让您无忧运维

    摘要:随着时代的发展,传统的“人工”运维方式,已经逐渐跟不上企业业务发展的需要.如何更好的保证数据库系统的稳定性.安全性.完整性和高性能,实现运维工具化.产品化.自助化.自动化,是当前数据管理和运维面 ...

  5. Asp.Net Core 3.1学习-读取、监听json配置文件(7)

    1.前言 文件配置提供程序默认的给我们提供了ini.json.Xml等.都是读取不同格式的文件.文件配置提供程序支持文件可寻.必选.文件变更的监视. 2.读取配置文件 主要运用的包:需要Ini.xml ...

  6. C++内存管理学习笔记(3)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  7. struts2 全局拦截器,显示请求方法和参数

    后台系统中应该需要一个功能那就是将每个请求的url地址和请求的参数log出来,方便系统调试和bug追踪,使用struts2时可以使用struts2的全局拦截器实现此功能: import java.ut ...

  8. ScheduleMaster新特性之延时任务初体验

    ScheduleMaster在上个月底更新到了2.0版本,在功能和代码以及文档上都往前跨了很大一步,详细信息可以参考这篇文章:https://www.cnblogs.com/hohoa/p/12772 ...

  9. shell 并行运行。

    我实在是太喜欢这个方法了.爽歪歪. 原帖 http://www.xaprb.com/blog/2009/05/01/an-easy-way-to-run-many-tasks-in-parallel/ ...

  10. python之Python Eclipse+PyDec下载和安装教程(超级详细)

    Eclipse 是著名的跨平台 IDE 工具,最初 Eclipse 是 IBM 支持开发的免费 Java 开发工具,2001 年 11 月贡献给开源社区,目前它由非盈利软件供应商联盟 Eclipse ...