概括
先概括下,Hive中出现OOM的异常原因大致分为以下几种:
1. Map阶段OOM。
2. Reduce阶段OOM。
3. Driver提交Job阶段OOM。
Map阶段OOM:
1. 发生OOM的几率很小,除非你程序的逻辑不正常,亦或是程序写的不高效,产生垃圾太多。
Reduce阶段OOM:
1. data skew 数据倾斜
data skew是引发这个的一个原因。
key分布不均匀,导致某一个reduce所处理的数据超过预期,导致jvm频繁GC。
2. value对象过多或者过大
某个reduce中的value堆积的对象过多,导致jvm频繁GC。
3.reduce内存不足
错误信息如下:Container [pid=26845,containerID=container_1419056923480_0212_02_000001] is running beyond virtual memory limits. Current usage: 262.8 MB of 2 GB physical memory used; 4.8 GB of 4.2 GB virtual memory used. Killing container.
解决办法:
1. 增加reduce个数,set mapred.reduce.tasks=300,。
2. 在hive-site.xml中设置,或者在hive shell里调大参数
set mapreduce.map.memory.mb=1024;
set mapreduce.map.java.opts=-Xmx819m;
set mapreduce.reduce.memory.mb=2048;
set mapreduce.reduce.java.opts=-Xmx1638m;
mapreduce.map.memory.mb是向RM申请的内存资源大小
mapreduce.reduce.java.opts 一般只用于配置JVM参数
JVM大小一般是所申请内存的0.75
3. 使用map join 代替 common join. 可以set hive.auto.convert.join = true
4. 设置 hive.optimize.skewjoin = true 来解决数据倾斜问题
Driver提交job阶段OOM:
job产生的执行计划的条目太多,比如扫描的分区过多,上到4k-6k个分区的时候,并且是好几张表的分区都很多时,这时做join。
究其原因,是 因为序列化时,会将这些分区,即hdfs文件路径,封装为Path对象,这样,如果对象太多了,而且Driver启动的时候设置的heap size太小,则会导致在Driver内序列化这些MapRedWork时,生成的对象太多,导致频繁GC,则会引发如下异常:
java.lang.OutOfMemoryError: GC overhead limit exceeded
at sun.nio.cs.UTF_8.newEncoder(UTF_8.java:53)
at java.beans.XMLEncoder.createString(XMLEncoder.java:572)
原因是因为扫描的表的分区太多,上到3千到6千个分区,这样在对计划进行序列化时,仅仅是路径对象Path就会耗去大半Driver,如果Driver设置的heap太小,甚至都会OOM。
解决思路:
1. 减少分区数量,将历史数据做成一张整合表,做成增量数据表,这样分区就很少了。
2. 调大Hive CLI Driver的heap size, 默认是256MB,调节成512MB或者更大。
具体做法是在bin/hive bin/hive-config里可以找到启动CLI的JVM OPTIONS。
这里我们设置
export HADOOP_HEAPSIZE=512