加载到 Hive 分区 Parquet 表时内存不足

Posted

技术标签:

【中文标题】加载到 Hive 分区 Parquet 表时内存不足【英文标题】:Out of memory when loading into Hive partitioned Parquet table 【发布时间】:2017-01-03 16:02:19 【问题描述】:

提前声明,这不是 Hadoop 的生产环境。这是我们正在测试工作流程的单节点环境

问题:尝试加载具有单个数据分区的 Parquet 表时,以下 Hive 查询失败。源表/分区只有一个 142MB 的文件。 insert 语句会生成一个映射器作业,该作业最终会因 Java 内存不足错误而失败。这个小测试用例似乎不应该产生这样的开销?

我们仅在尝试插入 Parquet 时遇到此问题。插入 Avro、Orc、Text 没有问题。查询也没有任何问题。

我尝试使用以下命令,但它们仅调整初始选择中使用的映射器。插入阶段仍然使用 1 个映射器。

set mapreduce.input.fileinputformat.split.minsize
set mapreduce.input.fileinputformat.split.maxsize
set mapreduce.job.maps

我使用的是 CDH 5.8 / Hadoop 2.6。 VM 实例有 4 个内核/24GB RAM 分配给它。

DROP TABLE IF EXISTS web.traffic_pageviews;

CREATE TABLE web.traffic_pageviews(
    SESSION_ID STRING,
    COOKIE_ID STRING,
    TS TIMESTAMP,
    PAGE STRING,
    PAGE_URL_BASE STRING,
    PAGE_URL_QUERY STRING,
    PAGE_REFERRAL_URL_BASE STRING,
    PAGE_REFERRAL_URL_QUERY STRING)
    PARTITIONED BY (DS STRING)
    STORED AS PARQUET;

INSERT OVERWRITE TABLE web.traffic_pageviews PARTITION(ds='2016-12-28')

select
    session_id,
    cookie_id,
    ts,
    page,
    SPLIT(PAGE_URL,'\\?')[0] PAGE_URL_BASE,
    SPLIT(PAGE_URL,'\\?')[1] PAGE_URL_QUERY,
    SPLIT(PAGE_REFERRAL_URL,'\\?')[0] PAGE_REFERRAL_URL_BASE,
    SPLIT(PAGE_REFERRAL_URL,'\\?')[1] PAGE_REFERRAL_URL_QUERY
from    
    web.stg_traffic_pageviews
where
    ds='2016-12-28';

错误输出如下所示。我觉得我们做错了什么,不应该调整 Java 内存分配?

2017-01-03 07:11:02,053 INFO [main] org.apache.hadoop.hive.ql.io.parquet.write.ParquetRecordWriterWrapper: real writer: parquet.hadoop.ParquetRecordWriter@755cce4b
2017-01-03 07:11:02,057 INFO [main] org.apache.hadoop.hive.ql.exec.FileSinkOperator: FS[1]: records written - 1
2017-01-03 07:11:02,062 INFO [main] org.apache.hadoop.hive.ql.exec.MapOperator: MAP[2]: records read - 1
2017-01-03 07:11:02,064 INFO [main] org.apache.hadoop.hive.ql.exec.FileSinkOperator: FS[1]: records written - 10
2017-01-03 07:11:02,064 INFO [main] org.apache.hadoop.hive.ql.exec.MapOperator: MAP[2]: records read - 10
2017-01-03 07:11:02,082 INFO [main] org.apache.hadoop.hive.ql.exec.FileSinkOperator: FS[1]: records written - 100
2017-01-03 07:11:02,082 INFO [main] org.apache.hadoop.hive.ql.exec.MapOperator: MAP[2]: records read - 100
2017-01-03 07:11:02,356 INFO [main] org.apache.hadoop.hive.ql.exec.FileSinkOperator: FS[1]: records written - 1000
2017-01-03 07:11:02,356 INFO [main] org.apache.hadoop.hive.ql.exec.MapOperator: MAP[2]: records read - 1000
2017-01-03 07:11:03,775 INFO [main] org.apache.hadoop.hive.ql.exec.FileSinkOperator: FS[1]: records written - 10000
2017-01-03 07:11:03,775 INFO [main] org.apache.hadoop.hive.ql.exec.MapOperator: MAP[2]: records read - 10000
2017-01-03 07:12:03,679 FATAL [LeaseRenewer:cloudera@quickstart.cloudera:8020] org.apache.hadoop.yarn.YarnUncaughtExceptionHandler: Thread Thread[LeaseRenewer:cloudera@quickstart.cloudera:8020,5,main] threw an Error.  Shutting down now...
java.lang.OutOfMemoryError: Java heap space

【问题讨论】:

可能是隐藏真正问题的愚蠢错误消息,如issues.apache.org/jira/browse/HADOOP-11172 (请注意,Cloudera 发行版有很多错误修复被移植到其所谓的 V2.6.0 - - 但不是全部;所以要知道这个问题在你的情况下是否仍然存在并不容易) 【参考方案1】:

在表上指定压缩后问题自行解决。具体来说:

CREATE TABLE web.traffic_pageviews(
    ...
    )
    PARTITIONED BY (DS STRING)
    STORED AS PARQUET
    TBLPROPERTIES ("parquet.compression"="SNAPPY");

虽然这是答案,但我不明白为什么它会起作用。如果有人有见解,将不胜感激。

【讨论】:

以上是关于加载到 Hive 分区 Parquet 表时内存不足的主要内容,如果未能解决你的问题,请参考以下文章

Hive中Parquet格式的使用

Hive 不读取 Spark 生成的分区 parquet 文件

使用Hive SQL插入动态分区的Parquet表OOM异常分析

Hive - 内存不足异常 - Java 堆空间

我们可以直接将 Parquet 文件加载到 Hive 中吗?

使用分区的雪花到 Hive 数据移动