19/08/12 14:15:35 ERROR cluster.YarnScheduler: Lost executor 5 on worker01.hadoop.mobile.cn: Container killed by YARN for exceeding memory limits. 5 GB of 5 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead.
在看這個問題之前,首先解釋下下面參數的含義:
hadoop yarn-site.xml部分資源定義相關參數,更詳細的內容可參考官網鏈接
yarn.nodemanager.resource.memory-mb //每個NodeManager可以供yarn調度(分配給container)的物理內存,單位MB yarn.nodemanager.resource.cpu-vcores //每個NodeManager可以供yarn調度(分配給container)的vcore個數 yarn.scheduler.maximum-allocation-mb //每個container能夠申請到的最大內存 yarn.scheduler.minimum-allocation-mb //每個container能夠申請到的最小內存,如果設置的值比該值小,默認就是該值 yarn.scheduler.increment-allocation-mb //container內存不夠用時一次性加多少內存 單位MB。CDH默認512M yarn.scheduler.minimum-allocation-vcores //每個container能夠申請到的最小vcore個數,如果設置的值比該值小,默認就是該值 yarn.scheduler.maximum-allocation-vcores //每個container能夠申請到的最大vcore個數。 yarn.nodemanager.pmem-check-enabled //是否對contanier實施物理內存限制,會通過一個線程去監控container內存使用情況,超過了container的內存限制以后,就會被kill掉。 yarn.nodemanager.vmem-check-enabled //是否對container實施虛擬內存限制
executor-memory和executor-memory-overhead源碼含義
EXECUTOR_MEMORY: Amount of memory to use per executor process EXECUTOR_MEMORY_OVERHEAD: The amount of off-heap memory to be allocated per executor in cluster mode
spark.yarn.executor.memoryOverhead源代碼實現:
val MEMORY_OVERHEAD_FACTOR = 0.10 val MEMORY_OVERHEAD_MIN = 384L
// Executor memory in MB. protected val executorMemory = sparkConf.get(EXECUTOR_MEMORY).toInt // Additional memory overhead. protected val memoryOverhead: Int = sparkConf.get(EXECUTOR_MEMORY_OVERHEAD).getOrElse( math.max((MEMORY_OVERHEAD_FACTOR * executorMemory).toInt, MEMORY_OVERHEAD_MIN)).toInt
到這里,可能有的同學大概就明白了,比如設置了--executor-memory為2G,為什么報錯時候是Container killed by YARN for exceeding memory limits. 2.5 GB of 2.5 GB physical memory used,2.5G從哪里來的?是這樣,首先計算出memoryOverhead 默認值是max(2G*0.1,384),也就是384M,又根據上面的yarn.scheduler.increment-allocation-mb值,就會分配2G+512M大小的container...
好了,我們再看問題,從報錯的描述上可以大概了解到,container超過了內存的限制從而被kill掉,從上面的參數yarn.nodemanager.pmem-check-enabled可以了解到該參數默認是true,也就是會由它來控制監控container的內存使用,所以第一步我們可以嘗試關閉該參數看應用是否可以正常運行
調整一:設置yarn.nodemanager.pmem-check-enabled=false
結果:應用成功運行,但是關閉了對container內存的監控,雖然可以運行,但是明顯沒有實際性的處理問題,而且不可控的內存使用,對多租戶的環境不友好
調整二:根據提示 Consider boosting spark.yarn.executor.memoryOverhead
但是什么是memoryOverhead呢? 如下圖:
container內存使用情況的時線圖:
嘗試提升spark.yarn.executor.memoryOverhead參數值至1.5G,可以看到container預留了更多空間給 OS overhead,沒有超過container的內存限制
不過很明顯,我們是犧牲內存資源來換取應用穩定性。
但是真正的原因到底是什么呢?看下圖:
每個任務都是通過NIO channel 去獲取shuffle文件。並且所需的緩沖區是從OS overheads中分配的,這也就導致了os overhead越來越大,因此我們也可以通過減少並行度來減少同時運行的任務來嘗試避免這樣的問題。
調整三:降低參數--excutor-cores值
結果也可以成功運行,但是同樣,我們是犧牲了應用的性能和cpu的利用率來換取應用穩定性。
最后,如果有同學單獨調整以上參數應用仍然不可用的話,可以嘗試上述多種方式同時使用,另外注意
1.對於發生shuffle的算子,比如groupby,可以通過repartition提升並行度
2.避免數據傾斜