如何解决当 Hive 输出查询结果时在 Amazon EMR 上发生的“OutOfMemoryError” Hive Java 堆空间异常?

上次更新时间:2020 年 5 月 18 日

我在 Amazon EMR 上运行 Apache Hive 查询。Hive 在输出查询结果时引发 OutOfMemoryError 异常。如何解决此问题?

简短描述

OutOfMemoryError 异常通常在 hive-server2、Hive 元存储或客户端没有足够的堆空间时在 INSERT OVERWRITE 命令期间发生。要解决此问题,请增加 JVM 的最大内存分配或提高 HADOOP_HEAPSIZE。

解决方法

使用以下一个或多个解决方案解决 OutOfMemoryError 异常。

注意:这些解决方法不涵盖在 Apache Tez 容器内存优化期间发生的 OutOfMemoryError 异常。

增加 JVM 的最大内存分配

当您启动 Hive shell 时,默认会分配 1GB 内存。最大内存分配由 -Xmx 参数定义。如果进程尝试使用超过最大值的内存,则 Hive 会尝试终止该进程并引发 OutOfMemoryError 异常。要解决此问题,请在 Hive shell 脚本中增大 -Xmx 值(单位 MB),然后再次运行 Hive 查询。

增加 HADOOP_HEAPSIZE

检查 /mnt/var/log/hive/user/hadoop/hive.log 中是否存在以下错误:

# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 12345"...
Killed

如果您发现此错误消息,则表示 JVM 堆空间已用尽内存。在 /etc/hive/conf/hive-env.sh 中为 Hive CLI 服务增加 HADOOP_HEAPSIZE,如以下示例所示。默认值为 1000。根据使用案例的需要增加它。然后,再次运行 Hive 查询。

export HADOOP_HEAPSIZE=2000

重要提示:重启这些服务后,此设置将应用于 hive-server2、Hive 元存储和 Hive CLI。(可选)您可以为每个服务设置单独的值。

Beeline 或 SQL Workbench/J

1.    如果您从 Beeline 或 SQL Workbench/J 运行相同的查询,请检查 /mnt/var/log/hive/hive-server2.loghive-server2.out 中是否存在堆空间垃圾收集错误。示例:

Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://emr-analytics_master.abc.aws.> select id, name, x.* from mydb.location a, curated_admin.nxpepnd1_tpn_prvdr_pra_fclt b, curated_admin.test_table c where a.test = b._id and a._id = b._id and b._prod_id = c.prod_f_id;
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 27745"...
Killed

2.    如果您发现此类错误,请在 /etc/hive/conf/hive-env.sh 中为 hive-server2 提高 HADOOP_HEAPSIZE。此设置也将应用于 Hive 元存储和 Hive 客户端。

export HADOOP_HEAPSIZE=2048

(可选)使用条件语句为 hive-server2、元存储和客户端指定不同的堆大小。示例:

export HIVE_CLIENT_HEAPSIZE=1024
export HIVE_METASTORE_HEAPSIZE=2048
export HIVE_SERVER2_HEAPSIZE=3072 
if [ "$SERVICE" = "metastore" ]
then
export HADOOP_HEAPSIZE=$HIVE_METASTORE_HEAPSIZE
elif [ "$SERVICE" = "hiveserver2" ]
then
export HADOOP_HEAPSIZE=$HIVE_SERVER2_HEAPSIZE
export HADOOP_OPTS="$HADOOP_OPTS -server -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/hive"
else
export HADOOP_HEAPSIZE=$HIVE_CLIENT_HEAPSIZE
fi

3.    更新这些设置后再次运行 Hive 查询。如果仍出现 OutOfMemoryError 异常,并且您正在同时运行多个客户端,请继续执行步骤 4。如果仍出现 OutOfMemoryError 异常,并且您未同时运行多个客户端,请跳到步骤 8。

4.    根据使用案例的需要为每个客户端增大 -Xmx 参数。

5.    选择适用于您的使用案例的垃圾收集器,方法是在 HADOOP_OPTS 行中添加 -XX:+UseParNewGC(新的并行垃圾收集器)或 -XX:+UseConcMarkSweepGC(并发标记扫描垃圾收集器),如以下示例所示。有关选择垃圾收集器的更多信息,请参阅 Java 文档中的垃圾收集Java HotSpot VM 选项

export HADOOP_HEAPSIZE=2048
if [ "$SERVICE" = "cli" ]; then
if [ -z "$DEBUG" ]; then
export HADOOP_OPTS="$HADOOP_OPTS -XX:NewRatio=12 -Xmx12288m -Xms10m -XX:MaxHeapFreeRatio=40 -XX:MinHeapFreeRatio=15 -XX:+useParNewGC -XX:-useGCOverheadLimit"
else
export HADOOP_OPTS="$HADOOP_OPTS -XX:NewRatio=12 -Xmx12288m -Xms10m -XX:MaxHeapFreeRatio=40 -XX:MinHeapFreeRatio=15 -XX:-useGCOverheadLimit"
fi
fi

6.    如果在指定的时间内未成功完成垃圾收集,则 Hive 会引发 OutOfMemoryError 异常。要删除时间限制,请删除 -XX:-UseGCOverheadLimit 或将其替换为 -XX:+UseGCOverheadLimit。(可选)修改 -XX:-UseGCOverheadLimit 以指定垃圾收集的新时间限制。有关更多信息,请参阅 Java 文档中的并行收集器

7.    再次运行 Hive 查询。如果 Hive 在运行时在终端上引发堆空间错误,或者如果 hive.log 或 hive-server2.log 中没有错误,则您的 Hive 客户端可能已用尽内存。示例:

Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://emr-analytics_master.abc.aws.> select id, name, x.* from mydb.location a, curated_admin.nxpepnd1_tpn_prvdr_pra_fclt b, curated_admin.test_table c where a.test = b._id and a._id = b._id and b._prod_id = c.prod_f_id;
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 27745"...
Killed

8.    要解决此错误,请增加客户端内存,然后再次运行查询。

9.    如果 Hive 仍引发 OutOfMemoryError 异常,请为您的客户端完成以下步骤。

Beeline:

默认情况下,在打印到 stdout 之前,Beeline 会尝试缓冲整个输出关系。如果输出关系很大,则此行为可能导致 OutOfMemoryError 异常。要解决 Beeline 中的 OutOfMemoryError 异常,请使用以下命令启动 Beeline,然后重试 Hive 查询:

beeline --incremental=true

SQL Workbench/J:

在 32 位 Java 运行时环境 (JRE) 中,默认情况下,应用程序最多可以使用 1 GB 的内存。在 64 位 JRE 中,默认情况下,应用程序最多可以使用 65% 的可用物理内存。要验证应用程序的可用内存量,请在选择帮助,然后选择关于

  • 对于 macOS:请根据需要在 Info.plist 文件中增大 -Xmx1024m 值。Info.plist 通常位于 /Applications/SQLWorkbenchJ2.app/Contents 目录下。例如,要将应用程序的可用内存量增加一倍,请将值从 -Xmx1024m 更改为 -Xmx2048m。然后,再次运行查询。
  • 对于 Windows:请创建 INI 文件,然后向该 INI 文件添加 vm.heapsize.preferred 参数,以增加应用程序的可用内存量。

如果您使用的是 Shell 脚本或批处理脚本,则可以在安装 SQL Workbench/J 时增加可用内存。以下示例中的命令将在安装期间创建 3 GB 的可用内存:

java -Xmx3g -jar sqlworkbench.jar

注意:如果 OutOfMemoryError 异常发生在客户端而不是 hive-server2 或 Hive CLI 上,请将输出保存到 Amazon Simple Storage Service (Amazon S3) 或 HDFS。请勿使用 Beeline 或 SQL Workbench/J 查看查询结果。

重启 Hive

如果您在 hive-site.xml 或 hive-env.sh 中修改 Hive 属性,您可能需要在更新的设置生效前重启 Hive。

对于 Amazon EMR 发行版本 4.7.0 及更高版本:

1.    使用 SSH 连接到主节点

2.    重启元存储:

sudo stop hive-hcatalog-server
sudo start hive-hcatalog-server
sudo status hive-hcatalog-server

注意:请勿尝试使用 sudo restart hive-hcatalog-server 命令重启元存储。

3.    重启 hive-server2:

sudo stop hive-server2
sudo start hive-server2
sudo status hive-server2

对于 Amazon EMR 发行版本 4.0.0 至 4.6:

1.    使用 SSH 连接到主节点

2.    重启元存储:

sudo stop hive-metastore
sudo start hive-metastore
sudo status hive-metastore

3.    重启 hive-server2:

sudo stop hive-server2
sudo start hive-server2
sudo status hive-server2