我想對 Amazon EMR 上 Spark 中的錯誤「容器因超出記憶體限制而被 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-core 選項減少執行程式內核的數量。
例如:
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
如果仍然收到錯誤訊息,請增加分割區的數量。
增加分割區的數量
若要增加分割區的數量,請為 Resilient Distributed Datasets 增加 spark.default.parallelism 的值,或執行 .repartition() 作業。增加分割區數量可減少每個分割區所需的記憶體容量。Spark 大量使用叢集 RAM 作為最大化速度的有效方法。因此,您必須使用 Ganglia 監控記憶體使用情況,然後驗證叢集設定和分割策略是否符合您不斷增長的資料需求。如果您仍然收到「容器因超出記憶體限制被 YARN 停止」錯誤訊息,請增加驅動程式和執行程式記憶體。
增加驅動程式和執行程式記憶體
如果錯誤發生在驅動程式容器或執行程式容器中,請考慮增加驅動程式或執行程式的記憶體,但不能同時增加兩者的記憶體。確保驅動程式或執行程式記憶體加上驅動程式或執行程式記憶體開銷的總和始終小於 EC2 執行個體類型的 yarn.nodemanager.resource.memory y-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 組態
如何解決 Amazon EMR 上 Spark 中的「java.lang.ClassNotFoundException」?