报错信息为map端的orc写入堆内存溢出相关错误,错误如下:
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: GC overhead limit exceeded
现设置如下参数解决:
set hive.exec.orc.default.compress.size=8192;
set mapreduce.map.memory.mb=2048;
set hive.exec.orc.default.buffer.size=16384;
set hive.exec.orc.skip.corrupt.data=true;
原因分析:
在ORC格式的hive表中,记录首先会被横向的切分为多个stripes,然后在每一个stripe内数据以列为单位进行存储。使用ORC文件格式时,用户可以使用HDFS的每一个block存储ORC文件的一个stripe。对于一个ORC文件来说,stripe的大小一般需要设置得比HDFS的block小,如果不这样的话,一个stripe就会分别在HDFS的多个block上,当读取这种数据时就会发生远程读数据的行为。如果设置stripe的只保存在一个block上的话,如果当前block上的剩余空间不足以存储下一个strpie,ORC的writer接下来会将数据打散保存在block剩余的空间上,直到这个block存满为止。这样,下一个stripe又会从下一个block开始存储。
当ORC writer写数据时,会将整个stripe保存在内存中。由于stripe的默认值一般比较大, 大尺寸的stripes使得从HDFS读数据更高效,但当有多个ORC writer同时写数据时,可能会导致内存不足。为了现在这种并发写时的内存消耗,ORC文件中引入了一个内存管理器。在一个Map或者Reduce任务中内存管理器会设置一个阈值,这个阈值会限制writer使用的总内存大小。当有新的writer需要写出数据时,会向内存管理器注册其大小(一般也就是stripe的大小),当内存管理器接收到的总注册大小超过阈值时,内存管理器会将stripe的实际大小按该writer注册的内存大小与总注册内存大小的比例进行缩小。当有writer关闭时,内存管理器会将其注册的内存从总注册内存中注销。
因此,考虑为orc写数据,会将stripe保持到内存中,而stripe的值大,导致内存溢出。每个stripe的默认大小为256MB。我们调小至64M,set hive.exec.orc.default.stripe.size=67108864;不报错了。