一、问题描述
执行语句‘insert into table xxx partition(dt) select …’ 向ORC格式的表中插入数据时报错:
1、'PHYSICAL' memory limit.
pid=21694,containerID=container_e122_1623983552034_0002_01_000279 is running 276889600B beyond the 'PHYSICAL' memory limit. Current usage: 16.3 GB of 16 GB physical memory used; 19.5 GB of 33.6 GB virtual memory used. Killing container.
2、java.lang.OutOfMemoryError: Java heap space
Error: Error while running task ( failure ) : java.lang.OutOfMemoryError: Java heap space
二、问题解决思路
1、解决'PHYSICAL' memory limit.
调整Tez Container Size
由原先16G 调整至20GB,解决了'PHYSICAL' memory limit问题,但是执行过程中报了另外的oom问题,参考第一章第2点。
2、解决java.lang.OutOfMemoryError: Java heap space
解决java.lang.OutOfMemoryError: Java heap space这个用异常花费时长较多,因为没有太多有用信息,先进行内存相关的调整:
调整:mapreduce.map.memory.mb 由4g调整至8g
调整:mapreduce.reduce.memory.mb由4g调整至8g
调整:mapreduce.map.java.opts 由-Xmx3276m调整至-Xmx6553m
调整:mapreduce.reduce.java.opts 由-Xmx3276m调整至-Xmx6553m
上述参数仍然报oom,后调整为16g依然报oom异常。
调整一下方向,拆分HSQL语句:
仅执行select …部分,查询没有问题。
执行insert into table xxx partition(dt) select …加上限制取1/2数据,依然报oom
执行insert into table xxx partition(dt) select …加上限制取1/4数据,依然报oom
后限制1/10执行插入成功。
问题成功定位,数据插入过程中map任务task内存不足,但是不可能无限增加内存,而且数据量并不大,还需要另辟蹊径。
查阅资料:
使用Hive SQL插入动态分区的Parquet表OOM异常分析 - 云+社区 - 腾讯云https://cloud.tencent.com/developer/article/1079007
启用hive.optimize.sort.dynamic.partition 参数后,问题得到解决
最终关键参数:
Tez Container Size 20g
For Map Join, per Map memory threshold 3822m
Map Memory 4g
Reduce Memory 4g
Sort Allocation Memory 2047m
MR Map Java Heap Size -Xmx3276m
MR Reduce Java Heap Size -Xmx3276m
Sort Partitions Dynamically true
hive.map.aggr false
如有需要可以在HSQL临时配置相关参数
三、问题思考
参考:使用Hive SQL插入动态分区的Parquet表OOM异常分析 - 云+社区 - 腾讯云https://cloud.tencent.com/developer/article/1079007
> show partitions test5;
> show create table test5;
ORC是列式批处理文件格式,格式要求在写入文件之前将批次的行(batches of rows)缓存在内存中。在执行INSERT语句时,动态分区目前实现是:至少为每个动态分区目录打开一个文件写入器(file writer)。由于缓冲区是按分区维护,因此在运行时所需的内存量随着分区数量的增加而增加。所以会导致mappers或reducers的OOM,具体取决于打开的文件写入器(file writer)的数量。
通过INSERT语句插入数据到动态分区表中,也可能会超过HDFS同时打开文件数的限制。
如果没有join或聚合,INSERT ... SELECT…语句会被转换为map任务作业。mapper任务会读取输入记录然后将它们发送到目标分区目录。在这种情况下,每个mapper必须为遇到的每个动态分区创建一个新的文件写入器(file writer),mapper在运行时所需的内存量随着分区数量的增加而增加。