AWS EMR 上 Spark 任务 Container killed Exit code 137 错误

一、问题描述

近期,使用 AWS EMR 集群上跑 Spark 任务时常出现 Container killed on request. Exit code is 137 这样的报错信息,导致任务运行失败

报错日志如下:

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-xxx-xxx-xx-xxx.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-xxx-xxx-xx-xxx.compute.internal. Exit status: 137. Diagnostics: Container killed on request. Exit code is 137

二、原因分析

看报错日志是因为 container 进程被杀,但是查看每个 executor 的内存使用情况后,发现每个 container 的 gc 时间都很合理,并没有任何 oom 的报错

然后根据丢失节点的 ip 信息找到对应节点的状态,发现其 status 为:dead,整体 gc 时常也很正常,光看日志只能得出一个结论:该任务失败是因为某个节点的 container 因为某个原因被强制停止导致的,这个原因无从下手

后续在 aws 的官网上找到了答案,具体描述如下:

当容器(Spark 执行程序)内存不足时,YARN 会自动将其终止。这会导致“根据要求终止容器。退出代码 137”错误。这些错误可能发生在不同的作业阶段,无论是窄还是宽转换。

说白了,还是内存不足,只不过在日志里查不到什么踪迹

三、解决方案

解决单个 executor 内存不足的方案非常多,大体思路有如下几点:

1,给 executor 加内存

--executor-memory xxg

2,增加数据分区数量

比如,spark 任务里有处理 10g 的数据,对应的 DataFrame 有 10 个分区,那么每个分区就有 1G 的大小,单个 task 处理的数据也就是 1G,这样给 Container 进程的内存带来较大压力

我们可以通过给这种数据进行重分区,比如将其分成 100 个分区,这样每个分区数据就只有 0.1G 了

val numPartitions = 100
val newDF = df.repartition(numPartitions)

3,增加 shuffle 分区数

道理第二点,只不过 spark 在 shuflle 后写出的分区数量是另外一个参数控制,如果不设置默认是 200,该参数配置如下:

//spark sql 中配置参数
spark.sql.shuffle.partitions=500
//使用代码时配置参数
spark.default.parallelism=500

4,减少 core 数量

每个 Container 进程里运行的线程数量越多,消耗的内存也会越大,所以可以通过降低每个 Container 内部运行的线程数来减低 Container 的内存消耗

参数配置如下:

--executor-cores 1

参考链接:退出代码 137 错误

你可能感兴趣的:(Spark,spark,大数据)