PS:解决方法只针对问题Hive Runtime Error: Map local work exhausted memroy,内存耗尽的错误。
前面说的都是解决问题过程,可自行跳过,解决方法在最后。
之前处理过的一个需求,有一批url需要撞库,url文件大小在50M左右,而需要撞库的表数据量比较大,所以考虑用mapjoin将小表放到内存中,避免reduce,提高速度,然而在启用的时候遇到了许多问题这里记录一下。
设置hive的自动加载小表大小
参数如下:
set hive.auto.convert.join=true; //设置自动选择MapJoin,默认是true
set hive.mapjoin.smalltable.filesize=1000000000; //设置mapjoin小表的文件大小为100M
默认值是25M,需改成100M之后就可以将本次的需求文件自动加载到内存进行mapjoin。
出现问题
根据问题提示的日志文件找到了以下描述:
Hive Runtime Error: Map local work exhausted memroy
说是内存不够了,好,那就加map任务内存呗。
调整map任务内存
set mapreduce.map.memory.mb=4096; //调整map task内存(map替换为reduce就是reduce)
然而调整之后上图中的max memory并没有任何变化,然后继续找
发现还有一个map任务的jvm内存参数,如下:
set mapred.child.java.opts=-Xmx1024m
set mapreduce.map.java.opts=-Xmx2048m
set mapreduce.reduce.java.opts=-Xmx2048m
set mapred.map.child.java.opts=-Xmx2048m
set mapred.reduce.child.java.opts=-Xmx2048m
上述三组参数,都是百度查到的,效果应该都是一样的,只不过因为hive的更新,导致设置参数的语句也在变化,有些语句设置在不同的版本可能会报错(没有深究,如有错误请指正),所以就都试一下吧。不过对这个问题来说,他们都没用,因为不管怎么设置,map memory参数还是没有变。
虽然问题没解决,不过倒是对这些内存了解了一下:
首先常用的几个内存:container的内存,task内存,task的jvm内存,jvm的堆内存。
container的内存默认为最大为8g,实际大小通过运行时指定的map或reduce内存来确定,然后是jvm的两个内存。关系应该是:
container内存 = map内存 = jvm内存> jvm堆内存
这些内存只是顺带提一嘴哈,当时百度的太多了,记不太清了。
远程dubug
既然上面那些内存都不是,那就只能debug来看一下调用的是哪个内存了,结果没想到hive debug也是这么坑,首先按网上说的,hive进调试模式,并打印控制台日志。
hive --debug --hiveconf hive.root.logger=DEBUG,console
然后idea建立远程连接,开始都很顺利,然后复现mapjoin的时候失败了,提示不能同时启动两个jvm,然后就在这卡了两天,各种百度,改启动文件,看源码,发现问题是,hive运行时首先会启动一个cli的jar包,就是交互界面的,然后跑mapreduce任务时候会再启动一个exec-driver的jar包,简单的select * 不会触发这个启动,但是稍微复杂一点启动job的话就会启动第二jar包,但这这两个jar包都是通过hadoop jar命令来启动的,启动时参数一样,所以导致任务失败。
我的解决办法是启动了hive cli之后,即进入hive交互界面之后,修改hadoop 的bin目录下hadoop启动脚本,
注释掉下面这一行:
HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
具体的原理我也没搞很明白,毕竟在这折腾了两天,整个人都废了,各种百度,东拼西凑的解决方法,就先这么用吧。
这样启动在运行sql语句后会提示在8000端口监听连接,然后再用idea启动一个远程连接就可以继续执行了。
源码
作为一名半吊子程序员,源码也是没搞太懂,不过按照错误日志给出的报错堆栈调用:
找到了MapRedLocalTask类,查找内存相关的参数时,看到了这么一段代码:
大概意思好像是说:本地任务运行时,jvm参数是无效的,默认读取parent jvm的参数,看到这里想了一下,难道这个parent jvm是运行hive cli的jvm?然后继续百度,hive在启动时果然是可以设置jvm的大小的。
问题解决
总结,mapjoin任务启动的是本地任务,而配置map内存或者jvm内存对本地任务是无效的,需要配置hive的启动jvm内存,方法有好几种:
一种是配置 hadoop-env.sh 具体参数名字忘记了,不过搜索一下“-Xmx”就能找到,里面没几个jvm的参数配置,默认的好像是512M,可以自己按需要修改
第二种修改hive-env配置文件,我没试这个,可以参考这篇文章:
https://www.cnblogs.com/jiangxiaoxian/p/6377471.html
第三种,最简单的方式,在启动hive客户端之前,修改一下变量
export HADOOP_CLIENT_OPTS="-Xmx1024m"
自己按需要修改大小就行,然后启动hive
问题解决!
最后提一点:语句中含有group by时会占用更多的内存,我的小表大小是50M,但是之前256M的内存都会报内存耗尽的错误,所以如果含有group by的话还是稍微调大一些。