火焰图--记一次cpu降温过程

引子   

  正值周末,娃儿6:30又如闹铃般准时来叫醒了咱们。年前离开美菜,又回到了杭州。本来是想有更多时间陪伴娃儿,然而新的工做节奏与工做地点,让咱们天天都是早上见面;这不,为了周末能够多玩一下子,早早就过来唤醒咱们。由于前几天咱们就约好了周末一块儿放风筝。有些事儿,我觉得只是随口一说,小孩子确真真的记着。html

  吃过早饭,拉着媳妇儿,领着娃,带上风筝就出门了。其实我是忐忑的,由于我也历来没有把风筝放起来过。来到草坪上,娃就拉着风筝如脱缰之马跑了起来。小孩子的幸福就这么简单,无关乎风筝能飞多高。java

                                 

 

  迎着暖暖朝阳,吹着徐徐春风,一会儿感受2周加班的疲惫都消散了。然而,一阵儿急促的“钉钉”声打破了可贵的宁静:Warning, ***applicaiton, cpu 高于51%,持续2分钟。此服务涉及大部分单车投放操做,目前是新老并用,咱们是新服务,tps不高,但业务很是重要。因而拉着还未尽兴的娃儿,回去处理问题了。固然个人心里是紧张而喜悦的,每次的故障就是一次学习的机会。git

 

问题分析  

  既然是cpu告警,首先查看cpu最近的使用状况,一看获得两条信息:1,下图中剪头所指的地方就是促发告警的阀值,2,cpu一直在40-50%上下徘徊 。程序员

 我想你们看到这个图也明白了:告警是正常的,目前cpu的状况很容易就会促发告警。反思一分钟:成天埋头支撑业务,连系统的如此重要指标都没有关注到。而后迅速回忆最近上线的功能,想到2月底,上线过电子锁的需求,可是系统已经没法查看2月分的cpu日志,接下来咱们须要去找出问题。github

 

排除内存缘由

  平时不多有处理生产环境cpu太高问题,真正碰到这样的场景仍是蒙圈的。看看网上好些帖子都是说: heap 内存不足,分配内存失败,会致使cpu偏高。首先使用jstat -gcutil 查看内存使用状况,以下图,可见 新生代的区域 survivor0, survivor1,  eden 以及老生代都正常,FGC 也正常。 json

 

 

jstat -gcutil 参数说明以下服务器

   

从新再来

   遇到问题,猜是须要经验的,瞎忙是没用的,既然没经验那就一步一步来验证吧;app

      1, ps -ef | grep java 找到进程id   27931jvm

  2,  top -H -p 9527 找到占cpu的线程svg

    

 

    3,  使用jstack 分别找也上面的线程的具体内容,好比第一个线程 28045

      a,  转化线程id为16进制   printf '%x\n' 28045,输出 6d8d, 由于jstack 中线程id 是16进制的。

      b,jstack  27931 | grep 6d8d ,找到此线程

     c, 再用一样的方法,发现其余几个线程也是 kafka 消费者引发的。

         

 

 

    

    4,知道问题在于消费kafka了,原来上次作电子锁需求时,为了拿到开锁结果,监听了一个kafka topic,这是一个特别核心的topic(后来听其余同事说,这是公司消息量最多的上个topic了),

随手查了下一个小时的数据26亿/h,也就是 70w/s,  如此巨大的tps, 而此服务只有两个结点,cpu维持在50%左右就不奇怪了。

 

  到这里,我还想再深究下,到底时哪几行代码占了cpu,  那应该如何找到这些代码呢。说来真是特别巧,上周5听了测试同窗的性能测试分享,后来还找时间了解了其中的火焰图(flame graph)和arthas , 对就是“火焰图”- 今天的主角儿。关于火焰图有几个基本的知识就能够简单分析了:  

1,y-axis 表示调用父子关系,下面函数是上面的parent;

2 x-axis 表示抽样合并的结果,越宽表示调用频率越高,即执行的时间长;

3 颜色,左右,没有特别的意义。

    一开始看到火焰图,也是特别蒙圈的,下面有几个文章特别不错,英文文档读起来不算太复杂,中文的彷佛就是翻译英文文档。

   英文文档:

 http://www.brendangregg.com/flamegraphs.html , https://queue.acm.org/detail.cfm?id=2927301

   中文说明:

   http://www.ruanyifeng.com/blog/2017/09/flame-graph.html

   火焰图demo:

 https://queue.acm.org/downloads/2016/Gregg7.svg

      

火焰图实践

   1,clone javaFlameGraph,git 地址以下:https://github.com/saquibkhan/javaFlameGraph

       有一个地方要特别注意下:javaFlameGraph 核心是调用 FlameGraph中的实现,如图中剪头所指的项目,要确保FlameGraph也下载了。

  

 

 

   2,拉出一个节点摘掉流量,上传clone的文件。

   3,到上传文件的所在目录执行  ./flame-gen.sh 27931  ,等待30s, control +c 就开始生成报告了。

       

 

 

   4,报告为当前目录下的  flame.html ,  找开就是生成的火焰图了。以下图。

  

      这个图是可交互的,能够点击每一个长方形获取更多详情的信息,如图,可看到有不少都是消耗都是 fastjson的 perseobject,由于咱们每收到一个消息,会使用fastjson解析,过滤出指定的消息。

 

 

       

 说明下其中几个除kafka相关线程外的线程,参考文章地址:https://blog.csdn.net/clamaa/article/details/70045983

  DestroyJavaVM:

执行main()的线程在main执行完后调用JNI中的 jni_DestroyJavaVM() 方法唤起DestroyJavaVM 线程。JVM在服务器启动以后,就会唤起DestroyJavaVM线程,处于等待状态,等待其它线程(java线程和native线程)退出时通知它卸载JVM。线程退出时,都会判断本身当前是不是整个JVM中最后一个非daemon线程,若是是,则通知DestroyJavaVM 线程卸载JVM。


  Surrogate Locker Thread:

这个线程主要用于配合CMS垃圾回收器使用,它是一个守护线程,其主要负责处理GC过程当中,Java层的Reference(指软引用、弱引用等等)与jvm 内部层面的对象状态同步。

     

结语

  由于工做的缘由,不多有机会处理高tps场景下的问题,终于理性的分析了一次生产环境cpu的问题,相信之后的再有这样的状况会从容一些。由于经验不足,文章中也有不少不足的地方,欢迎指出;若是以为有用,也欢迎点赞鼓励。

 

   成为一名优秀的程序员!

相关文章
相关标签/搜索