Spark到底是怎么確認內(nèi)存夠不夠用的?超大超詳細圖解!讓你掌握Spark memeoryStore內(nèi)存管理的精髓
首先回顧一下spark中的BlockManager和memoryStore是做什么的。
具體可以看這篇文章:
spark的內(nèi)存管理機制學(xué)習(xí)——BlockManager
他主要是將沒有序列化的java對象數(shù)組或者序列化的byteBuffer放到內(nèi)存中。
但是這就涉及到一些內(nèi)存管理的問題,如果放不下,是不是要放磁盤?什么時候認為放不下?這里會一一解讀。
MemoryStore的putIterator
這個方法是把一堆values的數(shù)組內(nèi)容放入內(nèi)存中(本質(zhì)上就是放到Map
如果發(fā)現(xiàn)內(nèi)存足夠,能夠申請,則調(diào)用putArray把數(shù)據(jù)寫入內(nèi)存(就是放到map中), 否則就去調(diào)用diskStore的接口寫入磁盤中。
這里我先打住,不直接往下講,而是給自己假設(shè)場景,如果是自己在開發(fā)計算引擎,寫executor里的block緩存,肯定需要思考這個問題:
什么時候認為內(nèi)存是足夠的?
最簡單的一個做法:
我給每個memoryStore設(shè)定一個閾值MaxMemory,
維護一個值currentMemory, 這個值就是memoryStroe里那個Map
然后遍歷計算一下輸入?yún)?shù)values所占的內(nèi)存大小 needMemory
如果needMemory > maxMemory - currentMemory, 則認為內(nèi)存不足,寫入到磁盤。
這個做法相當(dāng)于直接把整個values大小都計算好之后,如果ok,馬上進行寫入內(nèi)存操作。
如果是memoryStore是單線程的模塊那ok, 但如果這個putIterator是一個支持多線程寫入的模塊呢?
當(dāng)我覺得100M足夠,我寫入,可能得花10s, 然后另外一個線程也覺得100M足夠,也要寫入,結(jié)果寫到一半發(fā)現(xiàn)內(nèi)存不夠,就尷尬了。
因此問題變?yōu)椋?/p>
多線程時,如果確保計算的內(nèi)存量是有效的?
一種方式,就是每次確定要寫入時, 把要寫入的這100M的量直接加到currentMemory中。 ?后面的線程要判斷時,直接拿最新的curentMemory判斷。
但實際上這個數(shù)據(jù)并沒有真正寫入map中, 有可能中間出現(xiàn)寫入失敗或者線程中斷, 那這時候已經(jīng)被處理過的currentMemory就不好搞了。
所以引入一個概念,叫展開內(nèi)存unrollMemory。
每個線程都有自己的unrollMemory, 可以理解為該線程 準(zhǔn)備 寫入到內(nèi)存中的大小。
因此我們統(tǒng)計剩余可寫入內(nèi)存時, 實際上是等于 MaxMemory - currentMemory - 所有線程unrollMemory總和。
但是我們又不能讓線程展開的這個值正好把剩余內(nèi)存占滿,所以會設(shè)定一個展開內(nèi)存總和maxUnrollMemory,替代MaxMemory。
因此此時我這個線程可用的剩余內(nèi)存space,實際上為
maxUnrollMemory - ?cyrrentUnrollMemory。
但問題又來了,如果我們假想的可分配內(nèi)存比實際剩余內(nèi)存小,怎么辦?如下圖:
一種方式,是發(fā)現(xiàn)假想剩余內(nèi)存小于實際剩余內(nèi)存時,認為內(nèi)存不足,把數(shù)據(jù)寫入磁盤。
但有個問題, 假設(shè)我需要寫入100M, 實際剩余內(nèi)存是98M, 其實只差了2M, 那為什么不能擠擠呢?只差2M了!
然而我肯定不能去動其他線程的unrollMemory,畢竟人家都認為自己是ok的準(zhǔn)備寫入了,你總不能插隊吧?如果能動其他線程準(zhǔn)備寫入的數(shù)據(jù),這管理就太復(fù)雜了。
因此我們需要去已使用內(nèi)存MemoryEntry里面找, 找一下是不是有比較小的block塊,比如有一個塊只有5M, 那我就把這個block塊放入磁盤,那么我就可以塞進去了!
解答完上述問題后,再學(xué)習(xí)memoryStore的內(nèi)存寫入管理機制,就容易多了。
memoryStore完整安全展開流程
這里的計算不同于上文中提到的直接遍歷完之后判斷總大小
因為當(dāng)時傳入的是一個迭代器,只能迭代一次,每次迭代時都需要放入vector這個臨時存儲的列表中,萬一超級大,放入vector時超出范圍就GG了, 所以它實際時每隔一段就會檢查一下是否超出閾值。
2. 計算剩余可用的展開空間
下圖標(biāo)注的地方就是上文最后算出的space:
如果小于實際內(nèi)存,那么就需要去已分配的內(nèi)存中找,看下能不能選一些小朋友去磁盤中。
spark不足時,檢查能否抽一些已分配內(nèi)存區(qū)磁盤
核心方法來自ensureFreeSpace
我們看下它的實現(xiàn):
這個過程比較簡單,也沒做太多優(yōu)化,不考慮最優(yōu)情況,否則會有排序的性能問題。
如果發(fā)現(xiàn)抽內(nèi)存也不夠用, 那就直接認為不行了。
如果ok,那就認為可行,
內(nèi)存足夠分配,寫入
最后會返回一個vector數(shù)據(jù)
這個vector會拿去做真正的寫入操作。
完整高清大圖過程:
EI企業(yè)智能 可信智能計算服務(wù) TICS 大數(shù)據(jù) 智能數(shù)據(jù)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。