Spark優化那些事(4)-關於spark.driver.maxResultSize的疑惑

 

今天遇到了spark.driver.maxResultSize的異常,通過增大該值解決了,但是其運行機制不是很明白,先記錄在這裏,希望後面有機會可以明白背後的機制。

該異常會報如下的異常信息:

Job aborted due to stage failure: Total size of serialized results of 3979 tasks (1024.2 MB) is bigger than spark.driver.maxResultSize (1024.0 MB)

鎖定了是spark.driver.maxResultSize引起的,該參數控制worker送回driver的數據大小,一旦操過該限制,driver會終止執行。所以,我加大了該參數,結果執行成功。

問題就是,代碼裏不涉及大規模數據回傳,代碼如下

... // 省略

// 加載原始數據
val srcData = client.tdwSql(srcDB)
	.table(srcTable, Array("p_" + curDateObj.toString(formatPattern)))
	.filter("iworldid in (%s)".format(worldIdList.mkString(",")))
	.repartition(dataPart)
	.persist(StorageLevel.MEMORY_AND_DISK)
println("Original Data =============================")
srcData.show(10, false)  // 數據加載成功,打印前10行數據

//  計算數據尺寸
val allSize = srcData.map(r => r.getString(3).size + 24).sum   // 此處發生上面的異常
val sizeInG = allSize / 1e9
println(
	s"""
	   |size in bytes : $allSize
	   |size in GB: $sizeInG
			""".stripMargin)

... // 省略

RDD.sum處發生的異常,但個人認爲該action並不涉及大規模數據回傳。走讀了RDD代碼,根據代碼註釋,該action會分別在每個partition計算sum的值,然後將該值回傳給driver。設置了4000個分區,最多就4000個Long數據傳回來(32KB),不會操過1GB限制。原始數據有250G左右,所以重新分爲了4000個分區,提高併發計算。這個問題在Stackoverflow上也有,但是目前沒有可靠的答案。

使用的spark基礎配置如下

--num-executors 50
--driver-memory 10G
--executor-cores 2
--executor-memory 10G

spark.default.parallelism=200
spark.storage.memoryFraction=0.8
spark.network.timeout=600
spark.driver.maxResultSize=10G

問題本質

更新於2017-3-19

其實上面已經提到了問題的本質,之前driver內存設置爲1G,但是需要處理4000個分區,driver需要維護每個分區的狀態,分區越多,消耗的driver內存越多,最終導致了driver的Out-Of-Memeory異常。日誌裏面說的很明白,所當將driver內存設置爲10G後,問題迎刃而解。

Spark常見的兩類OOM問題:Driver OOM和Executor OOM。如果發生在executor,可以通過增加分區數量,減少每個executor負載。但是此時,會增加driver的負載。所以,可能同時需要增加driver內存。定位問題時,一定要先判斷是哪裏出現了OOM,對症下藥,才能事半功倍。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章