我想解决 Amazon EMR 上 Spark 中的错误“Container killed by YARN for exceeding memory limits”(容器因超出内存限制被 YARN 终止)。
简短描述
请使用以下方法之一解决此错误:
- 增加内存开销。
- 减少执行程序内核的数量。
- 减少分区的数量。
- 增加驱动程序或执行程序内存。
解决方法
此错误的根本原因和相应的解决方案取决于您的工作负载。您可能必须按以下顺序尝试以下每种方法来解决错误。在继续使用此序列中的下一个方法之前,撤消您在上一部分中对 spark-defaults.conf 所做的任何更改。
增加内存开销
内存开销是分配给每个执行程序的堆外内存量。默认情况下,内存开销设置为执行程序内存的 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。
例如:
sudo vim /etc/spark/conf/spark-defaults.conf
spark.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.default.parallelism 的值,或者运行 .repartition() 操作。增加分区数量会减少每个分区所需的内存量。Spark 大量使用集群 RAM 作为最大限度提高速度的有效方法。因此,您必须使用 Ganglia 监控内存使用情况,然后验证您的集群设置和分区策略是否满足不断增长的数据需求。如果您仍然收到“容器因超出内存限制被 YARN 终止”错误消息,请增加驱动程序和执行程序内存。
增加驱动程序和执行程序内存
如果错误发生在驱动程序容器或执行程序容器中,请考虑增加驱动程序或执行程序的内存,但不能同时增加两者的内存。确保驱动程序或执行程序内存加上驱动程序或执行程序内存开销的总和始终小于 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 实例类型:**您的 EC2 实例可能没有工作负载所需的内存资源。切换到更大的内存优化实例类型可能会解决错误。如果更改实例类型后仍出现内存异常,请尝试在新实例上使用故障排除方法。
相关信息
Spark configuration
如何解决 Amazon EMR 上 Spark 中的“java.lang.ClassNotFoundException”错误?