概述
现网内存问题定位总结
前段时间,现网遇到一个很奇葩的问题,server会莫名其妙的重启。个人功力有限,这个问题搞了好久才找到问题原因,现在就把此类问题的基本定位方法梳理一下,也算是一个总结吧。
搞java(或其他JVM语言)的人都知道,jdk里自带了几个很牛逼的工具(jmap/jstack/jstat),是定位java问题的利器,首先要知道这几个工具的使用,然后结合linux的相关工具(top/ps/vmstat等),再通过gc日志和程序日志的分析,逐步找到问题产生的原因。
一. JDK相关
(1) Jstat
此命令可以指定很多参数,可以查看gc和内存使用信息。如-class可以显示加载class数量,-gc可以动态显示java堆各区情况、gc次数等,-gcutil可以动态显示堆各区使用情况、gc次数等,-gccapacity可以查看各个区大小分配情况,我一般使用gc比较多,因为它显示的信息更详细更全。
(2) Jstack
此命令可以打印当前各线程栈信息,相当于程序的一个快照,可以看到各个进程都在做什么,对定位问题非常有用。
(3) Jmap
此命令可以对java堆进行更详细的解剖,-heap可以看各区分配和使用情况,-histo可以看各个类型所占用空间,-dump可以将当前进程dump下来,使用jhat或者Mat进行分析,定位内存泄露等问题。
(4) Jvm参数
Jvm有很多种gc类型可以选择,还有很多个参数。hive是用户相应为先的server,因此,我们选用的gc类型是:新生代ParNew,老年代CMS。还需要加上几个gc日志的参数,如-XX:+PrintGCDetails,-XX:+PrintGCDateStamps,-Xloggc:等,这里就不细说了。
二. 结合Linux的命令
(1) top
top命令可以看使用cpu/内存比较高的一些进程,加上-Hp可以看到一个进程里有哪些线程使用cpu比较高。
(2) ps
可以查看某个进程信息,如进程id、启动时间、内存使用等。
(3) netstat
看以查看端口使用信息,网卡信息等。
(4) grep/tail/head等
这几个工具是用来查看日志文件信息,在海量的日志中寻找到有用的信息,还要靠它们,合理利用它们会起到事半功倍的效果。
最主要用到的就是这几个命令,其他命令可以搭配使用。
三. 实战
(1) 背景
提交hive的sql执行过程中,会偶尔周期性地在某个时间段产生“断开的管道”错误,有时候会导致server挂掉,被监控重启。
(2) 定位过程
分析问题
刚开始以为是hdfs的客户端导致的问题,就请hdfs的同学帮忙看到底为什么产生此错误,hdfs的同学说此类问题是底层通信系统导致的问题,他们只能确定是底层通信断开了,才会出现这种情况。但是底层通信为什么会断开呢??
首先通过分析日志,发现产生此类错误的时间是聚集性的,就在一段时间内出现,其他时间段不会,然后,去查看日志文件,发现,出现此类问题的时候,程序在频繁的做fullGc,那么问题就明朗了,因为jvm在做fullGc会导致很多预想不到的问题。
Gc日志显示,各一两分钟就会做fullGc,再查gc的次数,发现一个小时内高达42次,这是很不正常的。那么,问题又来了,到底是什么导致如此频繁的fullGc呢??
追查问题
通过查看堆内存使用监控,看到,在23:06分左右,老年代内存突然飙涨,一直处于满的状态,这说明,在23:06分左右,肯定发生了一些事情,那么到底发生什么事情了呢??
hive是提供解析执行sql的服务,唯一可能的因素就是用户提交过来一条sql导致内存使用满。但是,hive有时会在一分钟内接受几百条sql,如下图,查看23:0开始的sql就有2K多,如何在这么多sql中找到问题sql呢??
想来想去,还是要从gc日志开刀,因为gc日志记录了最详细的内存使用信息。通过看gc日志,发现,内存的使用量是从23:03:03开始增长,之前是300+M,但是,到23:05分的时候,内存使用量已经涨到6G多,这里肯定有问题,还可以明显的将时间范围缩短为23:03和23:04。
通过grep工具对DayLog.log日志,进行筛选,将肯定不可能产生此问题的语句(如set、desc、show、alter等)去掉后,只剩下20多条sql语句,然后,挨个去执行,同时,使用jstat工具监控server端内存使用情况(jstat -gc 30875 2000 2000),最后,发现产生问题的sql。
验证问题
如下图,当执行此sql时,内存会飙涨,老年代使用量直接冲到顶,看gc日志,一直在做fullGc。(测试server使用参数-Xmx1000m -Xmn100m)
最后,发现此sql需要查询pg外表,而且pg外表的数据量很大,之前将hive连接pg外表的connect的autoCommit设置成true了,这样,所有查询的结果都会放在内存里,pg外表的数据量很大,肯定会把内存沾满。
(3) 结论
定位此问题花费了很久的时间,通过定位此问题,理解了jvm的cms的回收机制,学会查看gc日志的方法,并熟悉了相关工具的使用,同时通透了问题的定位流程。但是,同时也得到了教训:小改动也要进行记录,并进行严格的测试才能通过,否则很可能产生大问题。
四. 总结
还有其他定位方法,如使用jstack查看栈空间,通过top –Hp查看繁忙线程、通过分析dump文件定位内存泄露等。
心得:
产生问题不要慌,要耐心去分析,逐步去解决,这才是正确的方式。
做事要认真,要全面,不要因为小就疏忽。
附录:
CMS垃圾回收器简介
CMS(ConcurrentMark Sweep)收集器,是一种以获取最短回收停顿时间为目标的收集器,基于“标记-清除”算法。(很明显会产生内存碎片问题)
机制:
包含6个阶段:
①初始化标记(STW)
②并发标记
③并发预清理
④并发重新标记(STW)
⑤并发清理
⑥重置GC线程
CMS收集器会产生两次Stop the world(STW):①和④。
各步骤工作:
① 初始化标记,只会标记Gc Roots能到达的对象,速度很快。
② 并发标记,是GC root tracing过程。
③ 并发预清理,并发做下面重新标记的工作。
④ 重新标记,修复并发标记期间因程序运行导致标记变动的部分。
⑤ 开始实际清理垃圾
⑥ 重置gc线程
CMS也有一些缺点:
① 因为是并发收集器,对cpu资源非常敏感,并发收集,影响应用程序速度,导致吞吐量降低。cpu个数越少,影响越大。
② “浮动垃圾”问题。简单来说,浮动垃圾是指并发清理过程中产生的垃圾。因此,会预留一部分空间给程序使用,也就是老年代还没使用满就开始垃圾收集。要是在收集期间,预留的空间不够用,就会导致“Concurrent Mode Failure”失败,然后,会启动Serial Old收集器对老年代回收,这时停顿时间会更长。(上述分析的问题,就是产生大量的Concurrent Mode Failure错误)
③ 使用“标记-清除”算法,导致内存碎片产生,降低利用率。
关于CMS的一些配置说明,网上很多介绍,就不说明了。
最后
以上就是懦弱月光为你收集整理的Hive现网内存问题定位总结的全部内容,希望文章能够帮你解决Hive现网内存问题定位总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复