我在 Amazon EMR 上的 Apache Spark 作业失败,并出现“Container killed on request.Exit code is 137”错误。
简短描述
当容器(Spark 执行程序)耗尽内存时,YARN 会自动终止容器,您可能会收到以下错误:
“Container killed on request" stage failure: Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Task 2 in stage 3.0 failed 4 times, most recent failure: Lost task 2.3 in stage 3.0 (TID 23, ip-###-###-##-###.compute.internal, executor 4): ExecutorLostFailure (executor 4 exited caused by one of the running tasks) Reason: Container marked as failed: container_1516900607498_6585_01_000008 on host: ip-###-###-##-###.compute.internal.Exit status: 137.Diagnostics: Container killed on request.Exit code is 137”
解决方法
增加驱动程序或执行程序内存
要增加容器内存,请先连接集群的主节点,然后修改 Spark 配置文件 (spark-defaults.conf) 中的 spark.executor.memory 或 spark.driver.memory 参数。
正在运行的集群
要打开 spark-defaults.conf,请运行以下命令:
sudo vim /etc/spark/conf/spark-defaults.conf
要增加容器内存,请在 spark-defaults.conf 中添加或修改以下参数:
spark.executor.memory 10g
spark.driver.memory 10g
**注意:**根据集群的可用资源和工作负载要求,将 10g 替换为内存值。
单个作业
运行 spark-submit 时,使用 --executor-memory 或 --driver-memory 选项来增加内存。
示例:
spark-submit
--executor-memory 10g
--driver-memory 10g
...
**注意:**根据集群的可用资源和工作负载要求,将 10g 替换为适当的内存值。
添加更多 Spark 分区
如果无法增加容器内存(例如,在节点上使用的是 maximizeResourceAllocation),则可增加 Spark 分区的数量。这样可以减少单个 Spark 任务处理的数据量,从而减少单个执行程序使用的总内存。
要添加更多 Spark 分区,请先连接集群的主节点,然后在 Spark Shell 中运行以下命令:
val numPartitions = 500
val newDF = df.repartition(numPartitions)
**注意:**将 500 替换为适合您的数据大小的分区数量。
增加随机分区的数量
如果错误发生在广泛转换(例如 join 或 groupBy)期间,请先连接到集群的主节点,然后添加更多随机分区。默认值为 200。
正在运行的集群
要打开 spark-defaults.conf,请运行以下命令:
sudo vim /etc/spark/conf/spark-defaults.conf
更新配置文件中的随机分区:
spark.sql.shuffle.partitions 500
**注意:**将 500 替换为适合您的数据大小的分区数量。
单个作业
运行 spark-submit 时,使用 --conf spark.sql.shuffle.partitions 选项添加更多随机分区。
示例:
spark-submit
--conf
spark.sql.shuffle.partitions=500
...
减少执行程序内核的数量
当您减少执行程序内核的数量时,还会减少执行程序同时处理的最大任务数。由此可以减少容器使用的内存量。
正在运行的集群
首先连接到集群的主节点,然后在主节点上打开 spark-defaults.conf 文件:
sudo vim /etc/spark/conf/spark-defaults.conf
要设置执行程序内核的数量,请修改 spark.executor.cores 参数:
spark.executor.cores 1
**注意:**将 1 替换为使用案例所需的执行程序内核数。
单个作业
运行 spark-submit 时,使用 --executor-cores 选项减少执行程序内核的数量。
示例:
spark-submit
--executor-cores 1
...
增加实例大小
当操作系统内存不足时,操作系统 oom_reaper 也可能会终止 YARN 容器。如果这样导致错误,请使用具有更多 RAM 的更大实例。为确保 YARN 容器不会耗尽 Amazon Elastic Compute Cloud (Amazon EC2) 的所有 RAM,请降低 yarn.nodemanager.resource.memory-mb。
查看您的 Amazon EMR 实例日志中的 dmesg 命令输出,以确定 oom_reaper 是否导致了错误。首先,使用 YARM 资源管理器用户界面或日志来查找被终止的 YARN 容器运行的核心或任务节点。然后,查看容器被终止之前和之后此节点上的 Amazon EMR 实例状态日志,以确定导致进程终止的 oom_reaper。
在以下示例中,内核(Linux 的 OOM 终止程序)终止了 ID 为 36787 的进程,该进程对应于 YARN container_165487060318_0001_01_000244:
# hows the kernel lookingdmesg | tail -n 25
[ 3910.032284] Out of memory: Kill process 36787 (java) score 96 or sacrifice child
[ 3910.043627] Killed process 36787 (java) total-vm:15864568kB, anon-rss:13876204kB, file-rss:0kB, shmem-rss:0kB
[ 3910.748373] oom_reaper: reaped process 36787 (java), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
检查磁盘利用率和节点降级
如果前面的故障排除选项无法解决错误,请检查磁盘利用率和节点降级。使用实例状态日志中的 df-h 标志来检查集群和节点磁盘利用率。还可以在Amazon Health Dashboard 上查看节点状况。
相关信息
如何解决 Amazon EMR 上 Spark 中的错误“Container killed by YARN for exceeding memory limits”?
如何解决 Amazon EMR 上 Spark 作业中的阶段故障?