今天测试团队反馈说,服务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. Redis 6.0 新特性-多线程连环13问!

    Redis 6.0 来了 在全国一片祥和IT民工欢度五一节假日的时候,Redis 6.0不声不响地于5 月 2 日正式发布了,吓得我赶紧从床上爬起来,学无止境!学无止境! 对于6.0版本,Redis之 ...

  2. 2019-2020Nowcoder Girl初赛 题解

    题目都不是很难,就是最后一题有点毒瘤 第一题:牛妹爱整除 这个你把一个进制数进行拆分,拆分成若干位,然后在取模,这样会发现如果是x进制的数,那么对x+1这个进制转化即满足条件. 举个例子:一个x进制数 ...

  3. openCV从入门到放弃

    与图像处理之间的关系,opencv的简介和使用定位 如题...因为偶然的机会需要用到图像处理,像我这么爱学习 并且动手能力又强的人怎么能没有心得笔记呢,哇哈哈哈.非要说的low逼点这玩意儿这玩意儿就是 ...

  4. Linux(Ubuntu) MySQL数据库安装与卸载

    安装 修改远程访问 卸载 安装 首先检查系统中是否已经安装了MySQL sudo netstat -tap | grep mysql 没有显示已安装结果,则没有安装 如若已安装,可以选择删除.(删除方 ...

  5. keepalived高可用服务配置管理

    实验环境: 主机 ipaddress 服务 备注 k8s-master1 10.0.0.63 nginx k8s-master2 10.0.0.64 nginx k8s-node1 10.0.0.65 ...

  6. 036_python的大文件下载以及进度条展示

    复习 1.黏包现象 粘包现象的成因: tcp协议的特点,面向流的,为了保证可靠传输,所以有很多优化的机制. 无边界 所有在连接建立的基础上传递的数据之间没有界限. 收发消息很有可能不完全相等. 缓存机 ...

  7. leetcode_二叉树验证(BFS、哈希集合)

    题目描述: 二叉树上有 n 个节点,按从 0 到 n - 1 编号,其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]. 只有 所有 节点能够形成且 只 形成 ...

  8. Redis实现分布式锁(设计模式应用实战)

    笔者看过网络上各种各样使用redis实现分布式锁的代码,要么错误,要么片段化,没有一个完整的例子,借这个周末给大家总结一下redis实现分布式锁的两种机制 自旋锁和排他锁 鉴于实现锁的方式不同,那么这 ...

  9. 一阶RC高通滤波器详解(仿真+matlab+C语言实现)

    文章目录 预备知识 关于电容 HPF的推导 simulink 仿真 simulink 运行结果 matlab 实现 matlab 运行结果 C语言实现 如果本文帮到了你,帮忙点个赞: 如果本文帮到了你 ...

  10. Python自动生成100以内加减乘除混合运算题

    import random from random import choice ops = ('+','-','×','÷') ans = [] i=0 while i < 100 : op1 ...