從源碼幫你剖析: Spark 新舊內(nèi)存管理方案(下篇)
牛肉圓粉不加蔥 | 2016-07-28 11:38
【數(shù)據(jù)猿導讀】 上一篇文章【源碼剖析】- Spark 新舊內(nèi)存管理方案(上)介紹了舊的內(nèi)存管理方案以及其實現(xiàn)類 StaticMemoryManager 是如何工作的,本文將通過介紹 UnifiedMemoryManager 來介紹新內(nèi)存管理方案(以下統(tǒng)稱為新方案)

內(nèi)存總體分布
系統(tǒng)預留
在新方案中,內(nèi)存依然分為三塊,分別是系統(tǒng)預留、用于 storage、用于 execution。其中系統(tǒng)預留大小如下:
生產(chǎn)環(huán)境中使用一般不會設(shè)置 spark.testing.reservedMemory 和 spark.testing,所以我們認為系統(tǒng)預留空間大小置為 RESERVED_SYSTEM_MEMORY_BYTES,即 300M。
execution 和 storage 部分總大小
上一小節(jié)這段代碼是 UnifiedMemoryManager#getMaxMemory 的一個片段,該方法返回 execution 和 storage 可以共用的總空間,讓我們來看看這個方法的具體實現(xiàn):
從以上代碼及注釋我們可以看出,最終 execution 和 storage 的可用內(nèi)存之和為 (JVM最大可用內(nèi)存 – 系統(tǒng)預留內(nèi)存) * spark.memory.fraction,默認為(JVM 最大可用內(nèi)存 – 300M)* 0.75。舉個例子,如果你為 execution 設(shè)置了2G 內(nèi)存,那么 execution 和 storage 可用的總內(nèi)存為 (2048-300)*0.75=1311
execution 和 storage 部分默認大小
上一小節(jié)搞清了用于 execution 和 storage 的內(nèi)存之和 maxMemory,那么用于 execution 和 storage 的內(nèi)存分別為多少呢?看下面三段代碼:
object UnifiedMemoryManager 的 apply 方法用來構(gòu)造類 UnifiedMemoryManager 的實例
這段代碼確定在構(gòu)造 UnifiedMemoryManager 時:
maxMemory 即 execution 和 storage 能共用的內(nèi)存總和為 getMaxMemory(conf),即 (JVM最大可用內(nèi)存 – 系統(tǒng)預留內(nèi)存) * spark.memory.fraction
storageRegionSize 為 maxMemory * conf.getDouble(“spark.memory.storageFraction”, 0.5),在沒有設(shè)置 spark.memory.storageFraction 的情況下為一半的 maxMemory
那么 storageRegionSize 是干嘛用的呢?繼續(xù)看 UnifiedMemoryManager 和 MemoryManager構(gòu)造函數(shù):
我們不難發(fā)現(xiàn):
storageRegionSize 就是 storageMemory,大小為 maxMemory * conf.getDouble(“spark.memory.storageFraction”, 0.5),默認為 maxMemory * 0.5
execution 的大小為 maxMemory – storageRegionSize,默認為 maxMemory * 0.5,即默認情況下 storageMemory 和 execution 能用的內(nèi)存相同,各占一半
互相借用內(nèi)存
新方案與舊方案最大的不同是:舊方案中 execution 和 storage 可用的內(nèi)存是固定死的,即使一方內(nèi)存不夠用而另一方有大把空閑內(nèi)存,空閑一方也無法將結(jié)存借給不足一方,這樣降造成嚴重的內(nèi)存浪費。而新方案解決了這一點,execution 和 storage 之間的內(nèi)存可以互相借用,大大提供內(nèi)存利用率,也更好的滿足了不同資源側(cè)重的計算的需求
下面便來介紹新方案中內(nèi)存是如何互相借用的
acquireStorageMemory
先來看看 storage 從 execution 借用內(nèi)存是如何在分配 storage 內(nèi)存中發(fā)揮作用的
這一過程對應的實現(xiàn)是 UnifiedMemoryManager#acquireStorageMemory,上面的流程圖應該說明了是如何 storage 內(nèi)存及在 storage 內(nèi)存不足時是如何向 execution 借用內(nèi)存的
acquireExecutionMemory
該方法是給 execution 給指定 task 分配內(nèi)存的實現(xiàn),當 execution pool 內(nèi)存不足時,會從 storage pool 中借。該方法在某些情況下可能會阻塞直到有足夠空閑內(nèi)存。
在該方法內(nèi)部定義了兩個函數(shù):
maybeGrowExecutionPool:會釋放storage中保存的數(shù)據(jù),減小storage部分內(nèi)存大小,從而增大Execution部分
computeMaxExecutionPoolSize:計算在 storage 釋放內(nèi)存借給 execution 后,execution 部分的內(nèi)存大小
在定義了這兩個方法后,直接調(diào)用 ExecutionMemoryPool#acquireMemory 方法,acquireMemory方法會一直處理該 task 的請求,直到分配到足夠內(nèi)存或系統(tǒng)判斷無法滿足該請求為止。acquireMemory 方法內(nèi)部有一個死循環(huán),循環(huán)內(nèi)部邏輯如下:
從上面的流程圖中,我們可以知道當 execution pool 要為某個 task 分配內(nèi)存并且內(nèi)存不足時,會從 storage pool 中借用內(nèi)存,能借用的最大 size 為 storage 的空閑內(nèi)存+之前 storage 從 execution 借走的內(nèi)存。這與 storage 從 execution 借用內(nèi)存不同,storage 只能從 execution 借走空閑的內(nèi)存,不能借走 execution 中已在使用的從 storage 借來的內(nèi)存,源碼中的解釋是如果要這么做實現(xiàn)太過復雜,暫時不支持。
以上過程分析的是memoryMode 為 ON_HEAP 的情況,如果是 OFF_HEAP,則直接從 offHeapExecution 內(nèi)存池中分配,本文重點不在此,故不展開分析。
延伸閱讀
從源碼幫你剖析: Spark 新舊內(nèi)存管理方案(上篇)
來源:簡書
刷新相關(guān)文章
我要評論
活動推薦more >
- 2018 上海國際大數(shù)據(jù)產(chǎn)業(yè)高2018-12-03
- 2018上海國際計算機網(wǎng)絡(luò)及信2018-12-03
- 中國國際信息通信展覽會將于2018-09-26
- 第五屆FEA消費金融國際峰會62018-06-21
- 第五屆FEA消費金融國際峰會2018-06-21
- “無界區(qū)塊鏈技術(shù)峰會2018”2018-06-14
不容錯過的資訊
-
1#后疫情時代的新思考#疫情之下,關(guān)于醫(yī)
-
2眾盟科技獲ADMIC 2020金粲獎“年度汽車
-
3數(shù)據(jù)智能 無限未來—2020世界人工智能大
-
4#2020非凡大賞:數(shù)字化風起云涌時,共尋
-
5#榜樣的力量#天璣數(shù)據(jù)大腦疫情風險感知
-
6#榜樣的力量#內(nèi)蒙古自治區(qū)互聯(lián)網(wǎng)醫(yī)療服
-
7#榜樣的力量#實時新型肺炎疫情數(shù)據(jù)小程
-
8#榜樣的力量#華佗疫情防控平臺丨數(shù)據(jù)猿
-
9#后疫情時代的新思考#構(gòu)建工業(yè)互聯(lián)網(wǎng)新
-
102020可信云大會丨《云MSP發(fā)展白皮書》重