小站重新装修,欢迎到访。
归档 2013 年 9 月

Only support xterm terminal

前几天用我的Mac版iTerm2登陆服务器时terminal报出错误:

1
Error: only support xterm terminal

我看网上有人建议使用这个方案,其实是没找到病根。根据错误提示,我们应该用xterm类型的terminal登陆,所以正确的方案有二:

  • 设置环境变量export TERM=xterm

  • 修改你的ssh客户端的profile,设置terminal type为xterm

上述方式在我的iTerm2和Terminal都通过。

记一次Hive线上问题的排查

前几天监控到一个Hive Job CPU偏高,而且长时间无法停止,我最初怀疑是死循环,于是着手排查了下问题,不算太曲折。虽然已经过去多日,细节都快忘了,不过幸亏chrome的history里保留了一些痕迹,让我能把这件事分享出来。

由于权限有限,只能从运行Hive Job的这台机器查起。首先是要查看下对应的java进程的运行状况,用jstack,失败,抛出如下异常:

1
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: get_thread_regs failed for a lwp

首次见到,于是google之,得知是JDK6u23之前的一个bug(参考这里),查看了下故障机的JDK版本,果然低了,奇怪的是只有这台比较低,先不管,升级到1.6.0_31。

继续jstack,发现没有异常的锁等待。多次jstack查看,主线程都在这个方法里(代码行偶尔不同):

1
org.apache.hadoop.mapred.lib.CombineFileInputFormat.getMoreSplits(JobConf, Path[], long, long, long, List<CombineFileSplit>)

于是基本确定是在上述方法里发生了死循环,于是继续搜索:hadoop getMoreSplits infinite loop,发现社区有个相关的issue。关键是这句话:

At first, we lost some blocks by mis-operation . Then, one job tried to use these missing blocks. At that time getMoreSplits() goes into the infinite loop.

上面是因为mis-operation导致的,我没有听说有误操作发生,于是去读代码,同时汇报进展,同事听后告诉我确有一台DataNode挂掉了,那么如果确实是一台DataNode的宕机导致了block missing,则相关文件的replication应该为1,继续hadoop fs查看相关文件的replication,果不其然。

虽然不是十分明确地指出事故原因,但从一系列的分析来看,基本可以断定是上述原因。读了下上述issue提交的patch,大概的思路是在while(true)中检测是否出现了上述情况,如果出现的话,则强行忽略掉出问题的block,起初我还试图把这个patch打进来,但转念一想,这样会导致出现数据丢失,根本就不治本,问题的实质不是hadoop的错,而是hadoop的使用者没能很好地理解HDFS,在hadoop的世界里,错误是常态,虽然hadoop允许将replication设置为1,但用户必须明白的是hadoop没有义务也没有能力确保用户数据万无一失,用户必须学会通过设置合适的参数来避免单点问题。最终我给出了两条建议:

  • 严禁用户将replication设置为1
  • 加强线上机器监控

Java堆外内存泄露场景总结

去年在一次QA对我们的一台长连接服务器进行压测后,暴露了一个Java内存泄露问题,结合jconsole、jmap等一系列工具分析和代码review,最后发现是一个存放断开的Socket连接的容器,没有合适的清理释放逻辑。这是在java heap上发生的泄露,如果发生了non-heap上的内存泄露,一般会祭上google-perftools来分析。但不像堆上的泄露原因各种各样,non-heap的泄露原因比较常见的只有几种,因为日常开发中很少有机会操作non-heap内存。

这里总结一下java的non-heap内存泄露原因。其实说白了也就是介绍下日常开发中,哪里有可能接触到non-heap,哪些东西是放到non-heap上的。

####JNI

使用JNI有时为了提高效率,对于这种情况,如果效率提升不是非常大的话,我个人还是建议使用纯Java来替代JNI。正如我去年做的,兄弟部门把人脸识别的判决算法封装到JNI里,而我一向对自己写JNI不太放心,为了降低风险提高系统稳定性,干脆将核心算法翻译成Java了。但对于不得不使用JNI的场景,一定要注意内存的管理,但对于NewStringUTF()这种方法调用,则无需多虑,因为这其实是在java heap上创建Java对象。

####NIO

Java的nio有三种方法创建ByteBuffer:wrap(byte[])allocate(int)allocateDirect(int),第三种方法是在堆外申请内存,在使用较大块buffer的时候,能获得较高的效率。不过这种方式申请的内存可以被GC,但是如果使用不当导致泄漏,则比较难查找。

对于Oracle的HotSpot VM,可以用-XX:MaxDirectMemorySize指定direct buffer的最大值,这个默认值是0,即不限制。

说句题外话,Oracle的JDK7去掉了allocateDirect所分配内存的页对齐,这样可以减小分配很多小buffer的内存消耗。

####AWT/Swing
二者的一些bug会导致堆内存泄露,对于AWT/Swing引起的堆外内存泄露,我倒没什么经验,摘一个别人发的例子:

1
2
java.awt.Font font = java.awt.Font.createFont(Font.TRUETYPE_FONT, file);
font.deriveFont(Font.PLAIN, i)

至于哪些数据在堆外分配,读者可以阅读下源码分析下。对于这种情况,可以使用singleton模式解决。

####Inflater&Deflater

Java的zip包里两个重要类,记住一定要保证end()能被调用。这个可能比较常见一些,在此就不多做解释了。

1
2
3
4
5
6
7
8
9
10
11
Inflater inflater = null;
Deflater deflater = null;
try{
inflater = new Inflater();
deflater = new Deflater();
}catch(Exception e){
;
}finally{
inflater.end();
deflater.end();
}

以上就是四种比较常见的non-heap内存泄露原因,如果你的程序有堆外内存泄露的现象,可以着重从上述四个方面查找原因。

博主是一个不是很聪明的码农。完美主义者,强迫症中期。这里会记录一些回忆和点滴,以博为镜。

武器库:

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-SA 3.0  授权发布。最后生成于 2017-02-20.