我想对 Amazon EMR 上 Spark 中的 "Container killed by YARN for exceeding memory limits" 错误进行故障排除。
解决方法
此错误的根本原因和相应的解决方案取决于您的工作负载。要对此错误进行故障排除,请按以下顺序使用以下故障排除方法。
增加内存开销
内存开销是分配给每个执行程序的堆外内存量。默认情况下,Spark 会将内存开销设置为执行程序内存的 10% 或 384,以较高者为准。Java NIO 直接缓冲区、线程堆栈、共享原生库以及内存映射文件都会使用这部分内存开销。
逐渐增加内存开销,最高可达 25%。驱动程序或执行程序内存与内存开销的总和必须小于您的实例类型的 yarn.nodemanager.resource.memory-mb:
"spark.driver/executor.memory + spark.driver/executor.memoryOverhead < yarn.nodemanager.resource.memory-mb"
如果错误发生在驱动程序容器或执行程序容器中,则仅增加发生错误的容器的内存开销。您可以增加正在运行的集群、新集群或提交任务时的内存开销。
正在运行的集群
修改主节点上的 spark-defaults.conf。
例如:
sudo vim /etc/spark/conf/spark-defaults.conf
spark.driver.memoryOverhead 512
spark.executor.memoryOverhead 512
新集群
启动集群时,请添加配置对象,类似于以下示例:
[
{
"Classification": "spark-defaults",
"Properties": {
"spark.driver.memoryOverhead": "512",
"spark.executor.memoryOverhead": "512"
}
}
]
单个作业
要在运行 spark-submit 时增加内存开销,请使用 --conf 选项。
示例:
spark-submit --class org.apache.spark.examples.SparkPi --master yarn --deploy-mode cluster --conf spark.driver.memoryOverhead=512 --conf spark.executor.memoryOverhead=512 /usr/lib/spark/examples/jars/spark-examples.jar 100
如果在增加内存开销后仍然收到此错误,则减少执行程序内核的数量。
减少执行程序内核的数量
**注意:**撤消您在上一部分中对 spark-defaults.conf 所做的任何更改。
当您减少执行程序内核的数量时,同时会减少执行程序可执行的最大任务数,从而减少所需的内存量。根据引发此错误的驱动程序容器或出现此错误的其他执行程序容器,请相应减少驱动程序或执行程序的内核。
正在运行的集群
修改主节点上的 spark-defaults.conf。
示例:
sudo vim /etc/spark/conf/spark-defaults.confspark.driver.cores 3
spark.executor.cores 3
新集群
启动集群时,请添加配置对象,类似于以下示例:
[
{
"Classification": "spark-defaults",
"Properties": {"spark.driver.cores" : "3",
"spark.executor.cores": "3"
}
}
]
单个作业
要在运行 spark-submit 时减少执行程序内核的数量,请使用 —executor-cores 选项。
示例:
spark-submit --class org.apache.spark.examples.SparkPi --master yarn --deploy-mode cluster --executor-cores 3 --driver-cores 3 /usr/lib/spark/examples/jars/spark-examples.jar 100
如果您仍然收到错误消息,请增加分区数量。
增加分区数量
**注意:**撤消您在上一部分中对 spark-defaults.conf 所做的任何更改。
要增加分区数量,请增加原始弹性分布式数据集的 spark.default.parallelism 的值,或者运行 .repartition() 操作。
当您增加分区数量时,也会相应减少每个分区所需的内存量。Spark 大量使用集群 RAM 作为最大限度提高速度的有效方法。因此,您必须使用 Ganglia(适用于 Amazon EMR 版本 6.15)或 Amazon CloudWatch 代理(适用于 Amazon EMR 7.0 及更高版本)监控内存使用情况。然后验证您的集群设置和分区策略是否满足不断增长的数据需求。如果您仍然收到 "Container killed by YARN for exceeding memory limits" 错误消息,请增加驱动程序和执行程序内存。
增加驱动程序和执行程序内存
**注意:**撤消您在上一部分中对 spark-defaults.conf 所做的任何更改。
如果错误发生在驱动程序容器或执行程序容器中,请相应增加驱动程序或执行程序的内存,但不能同时增加两者的内存。确保驱动程序或执行程序内存加上驱动程序或执行程序内存开销的总和始终小于 EC2 实例类型的 yarn.nodemanager.resource.memory-mb 的值:
"spark.driver/executor.memory + spark.driver/executor.memoryOverhead < yarn.nodemanager.resource.memory-mb"
正在运行的集群
修改主节点上的 spark-defaults.conf。
示例:
sudo vim /etc/spark/conf/spark-defaults.conf
spark.executor.memory 1g
spark.driver.memory 1g
新集群
启动集群时,请添加配置对象,类似于以下内容:
[
{
"Classification": "spark-defaults",
"Properties": {
"spark.executor.memory": "1g",
"spark.driver.memory":"1g",
}
}
]
单个作业
运行 spark-submit 时,使用 --executor-memory 和 --driver-memory 选项来增加内存。
示例:
spark-submit --class org.apache.spark.examples.SparkPi --master yarn --deploy-mode cluster --executor-memory 1g --driver-memory 1g /usr/lib/spark/examples/jars/spark-examples.jar 100
其他故障排除步骤:
如果您仍然收到错误消息,请执行以下操作:
- 针对示例数据集运行应用程序。最佳做法是进行基准测试,它可以帮助您发现导致内存问题的性能下降和分区倾斜情况。
- 处理所需的最少量数据。如果您不筛选数据,或者在应用程序运行的后期进行筛选,则过多的数据可能会减慢应用程序的运行速度。这会增加内存异常的几率。
- 对数据进行分区,仅摄取所需的数据。
- 使用不同的分区策略。例如,使用备用键进行分区以避免分区过大和分区倾斜。
- 您的 EC2 实例可能没有工作负载所需的内存资源。切换到更大的内存优化实例类型。如果更改实例类型后仍出现内存异常,请尝试在新实例上使用故障排除方法。
相关信息
Apache Spark 网站上的 Spark configuration(Spark 配置)
如何解决 Amazon EMR 上 Spark 中的 "java.lang.ClassNotFoundException" 错误?