为什么我的 AWS Glue ETL 任务失败并显示错误“Container killed by YARN for exceeding memory limits”?

上次更新日期:2021 年 7 月 21 日

我的 AWS Glue 提取、转换和加载 (ETL) 任务失败,并且显示错误“Container killed by YARN for exceeding memory limits”。

简短描述

造成此错误的最常见原因如下:

  • 内存密集型操作,例如连接大型表或处理特定列值分布偏差的数据集,超过了基础 Spark 集群的内存阈值
  • 数据 FAT 分区的内存耗用量超过分配给相应执行程序的内存
  • 无法拆分的大文件导致内存中分区较大

解决方法

使用以下一种或多种解决方案以解决此错误:

  • 将工作线程类型从 G1.x 升级到具有更高内存配置的 G2.x。有关工作线程类型规格的详细信息,请参阅定义 Spark 任务的任务属性中的工作线程类型部分。您还可以查看下表以了解有关工作线程类型规格的信息:
标准 spark.executor.memory:5g
spark.driver.memory:5g
spark.executor.cores:4
G1.x spark.executor.memory:10g
spark.driver.memory:10g
spark.executor.cores:8
G2.x spark.executor.memory:20g
spark.driver.memory:20g
spark.executor.cores:16
  • 如果升级工作线程类型后错误仍然存在,则增加任务的执行程序数量。每个执行程序都有一定数量的内核。此数字决定了执行程序可以处理的分区数。数据处理单元 (DPU) 的 Spark 配置是根据工作线程类型定义的。
  • 确保数据已正确得到并行处理,以便在任何随机操作 (例如连接) 之前均匀使用执行程序。您可以在所有执行程序之间重新分区数据。可以在 ETL 任务中分别包含以下适用于 AWS Glue DynamicFrame 和 Spark DataFrame 的命令来实现这一点。
dynamicFrame.repartition(totalNumberOfExecutorCores)
dataframe.repartition(totalNumberOfExecutorCores)
  • 使用任务书签仅允许 AWS Glue 任务处理新写入的文件。这可以减少 AWS Glue 任务处理的文件量,并缓解内存问题。书签存储有关上次运行中所处理文件的元数据。在随后的运行中,任务会比较时间戳,然后决定是否再次处理这些文件。有关详细信息,请参阅使用任务书签跟踪处理的数据
  • 在连接到 JDBC 表时,默认情况下,Spark 仅打开一个并发连接。驱动程序尝试在单个 Spark 执行程序中同时下载整个表。这可能需要更长的时间,甚至会导致执行程序的内存不足错误。相反,您可以设置 JDBC 表的特定属性,以指示 AWS Glue 通过 DynamicFrame 并行读取数据。有关更多信息,请参阅并行读取 JDBC 表。或者,您可以通过 Spark DataFrame 从 JDBC 实现并行读取。有关更多信息,请参阅 Spark DataFrame 并行从 JDBC 读取,并查看属性,例如 partitionColumnlowerBoundupperBoundnumPartitions
  • 避免在 ETL 任务中使用用户定义的函数,尤其是在将 Python/Scala 代码与 Spark 的函数和方法结合使用时。例如,避免使用 Spark 的 df.count() 来验证 if/else 语句或 for 循环中的空 DataFrames。相反,请使用更优性能的函数,例如 df.schema ()df.rdd.isEmpty()
  • 开发端点上测试 AWS Glue 任务,并相应地优化 ETL 代码。
  • 如果上述解决方案选项都不起作用,请将输入数据拆分为块或分区。然后,运行多个 AWS Glue ETL 任务,而不是运行一个大型任务。有关更多信息,请参阅有限执行的工作负载分区