共计 2543 个字符,预计需要花费 7 分钟才能阅读完成。
这期内容当中丸趣 TV 小编将会给大家带来有关如何解决 JobTracker Heap 的 OOM 问题,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
引子
最近新上了 9107 渠道的实验。
从实验方法上,相比于之前的 9105 渠道只是简单地对过去 6 小时的正例数据进行翻倍,9107 则以当前时间为基准,使用指数函数对合并后训练数据中的正例进行增益。
从具体的实现而言,为了实现的简单,实验的 ETL 部分依旧沿用 Hadoop 进行 ETL 合并处理,但后续的 Sampling 和 Filtering 则采用 python 单机实现。经过流程和数据测试无误后上线,但结果老集群的 JobTracher 总是在跑了 70 多个 Job 之后就报出 Heap OOM 异常 (java.lang.OutOfMemoryError: Java heap space)。
解决过程
直接 google
在 statckoverflow 中有人建议调整 HADOOP_CLIENT_OPT,通过增大其 Xmx 解决该问题,经过尝试后发现无效果。
突然发现 java_pidxxxxx.hprof 文件,搜索相关资料,发现 Eclipse 中的 MAT 工具,分析可能为 JT 的问题
hprof 为当虚拟机中发生 OOM 错误时,自动对 Heap 进行转储生成的二进制文件。在启动进程时,可以通过添加参数 -XX:+HeapDumpOnOutOfMemoryError 开启该功能。
MAT(Memory Analyzer) 为 Eclipse 中一分析 hprof 文件的工具,可以通过 Eclipse 中的 Install New Software 进行集成。需要注意的一点是,当生成的 hprof 文件过大的时候,需要适当增大 eclipse 的启动 Xmx,其配置文件为安装目录下的 eclipse.ini。
通过 MAT 打开生成的 hprof 文件,如下图所示,会给出几条 Problem Suspect,在本文中,说明是由于 JobTracker 的占用内存过大导致的 OOM。
但是之前 JobTracker 稳定运行了好长时间,很少发生过该种现象,所以继续尝试使用 MAT 进行进一步的分析。通过对 dominator tree 一项进行分析发现,JobTracker 中绝大部分的内存都是由 JobInProgress 占用的,其结果如下图所示。
至此,问题算是已经定位出来,但是之前的 JobTracker 跑了上千的 Job 也从来没有发生过该种问题,为什么这次只跑了 70+ 个 Job 就发生了这种情况。
翻阅 Hadoop 技术内幕,了解 JobTracker 的主要作用
google 搜索并没有这方面很好地解答,就找了 Hadoop 技术内幕 一书中关于 JobTracker 的一章节进行学习。有一点特别引起了我的注意,原来 JobTracker 在启动的时候会启动一些重要的线程和服务,其中有一个 retireJobsThread 线程。
对于 retireJobsThread 线程而言,它可以清理长时间驻留在内存的已经运行结束的 Job 信息 (即 JobInProgress 对象的信息)。而将 JobInProgress 对象保存在内存中,则是为了方便外部对历史的 Job 信息进行查询。但由于 JobInProgress 对象会占用过多的内存,所以当 Job 同时满足条件 a,b 或是 a,c 时,就会被标志为过期的作业。
Job 已经完成,即状态为 SUCCEEDED,FAILED 或 KILLED
Job 完成时间距离当前已经 24 小时(可以通过 mapred.jobtracker.retirejob.interval 调整)
Job 拥有者已完成的 Job 数量大于 100(可以通过 mapred.jobtracker.completeuserjobs.maximum 调整)
显然正是由于 Job 的 retire 机制,避免了 JobTracker 占用内存的无线膨胀。虽然解决了 JobTracker 占用内存的无限膨胀问题,但是为什么之前的 JobTracker 就能维护 100 个 JobInProgress,而现在就不可以了呢?9105 和 9107 渠道到底差到了什么地方了呢?
突然间,想到了是不是由于 ETL Job 占用的内存信息过大,导致当前 2G 的 HeapSize 放不下这 100 条 JobInProgress 信息呢。于是,将 hadoop-env.sh 中的 HADOOP_HEAPSIZE 从 2000 调整到了 4000,问题神奇的就没有再出现过。那么究竟是为什么 ETL Job 会比 Sampling Job 和 Filtering Job 占用更多的内存呢?于是就有了最后一步 …
实际实验测试,使用 jmap 生成 hprof 文件,分析与预期的结果
在集群平稳的运行了 100+ 个 Job 之后,使用 jmap 工具 dump 出来了一份 JobTracker 的 hprof 文件。再次使用 MAT 对其进行分析,结果如下图所示:
由图可以看出以下几点:
JobTracker 的内存占用一直保持在 1.7G 左右
针对于 JobInProgress 占用内存过大的原因,完全是由于其需要调度的 TaskInProgress 过多(一般为 2K-3K 个),从而比 Sampling 和 Filtering 耗费掉更多的内存
至此,问题解决,确实是因为 9107 渠道只保留了 9105 渠道的 ETL Job,导致多个 ETL JobInPregress 累计占用内存远大于之前的 9105 实验,从而造成 JobTracker 一直产生 OOM 错误。
心得总结
说起来,问题的解决多多少少还是存在一定的偶然性,归根结底还是在于对 Hadoop 平台一些基础组件的底层实现不熟悉,从而导致问题定位慢,走了不少的弯路
MAT 确实是一个特别强大的工具,针对于 JVM 的 OOM 错误而言,通过使用 MAT 能够非常方便的定位问题的根结。后续对 MAT 的学习使用还需要进一步的加强。
对于正常运行中的 java 进程,可以使用 jmap 的 jmap -dump:format=b,file=xx pid 命令生成 hprof 文件,从而分析某一时刻进程中内存的详细使用情况
上述就是丸趣 TV 小编为大家分享的如何解决 JobTracker Heap 的 OOM 问题了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注丸趣 TV 行业资讯频道。