圖解Spark原理之memoryStore如何管理內存的寫入

首先回顧一下memoryStore是做什麼的。
他主要是將沒有序列化的java對象數組或者序列化的byteBuffer放到內存中。
但是這就涉及到一些內存管理的問題,如果放不下,是不是要放磁盤?什麼時候認爲放不下?這裏會一一解讀。

MemoryStore的putIterator

這個方法是把一堆values的數組內容放入內存中(本質上就是放到Map<blockId, blockEntry>中。
如果發現內存足夠,能夠申請,則調用putArray把數據寫入內存(就是放到map中), 否則就去調用diskStore的接口寫入磁盤中。
在這裏插入圖片描述
這裏我先打住,不直接往下講,而是給自己假設場景,如果是自己在開發計算引擎,寫executor裏的block緩存,肯定需要思考這個問題:

什麼時候認爲內存是足夠的?

最簡單的一個做法:

  1. 我給每個memoryStore設定一個閾值MaxMemory,
  2. 維護一個值currentMemory, 這個值就是memoryStroe裏那個Map<BlockId,memoryEntry>所佔的大小。
  3. 然後遍歷計算一下輸入參數values所佔的內存大小 needMemory
  4. 如果needMemory > maxMemory - currentMemory, 則認爲內存不足,寫入到磁盤。

這個做法相當於直接把整個values大小都計算好之後,如果ok,馬上進行寫入內存操作。
如果是memoryStore是單線程的模塊那ok, 但如果這個putIterator是一個支持多線程寫入的模塊呢?
當我覺得100M足夠,我寫入,可能得花10s, 然後另外一個線程也覺得100M足夠,也要寫入,結果寫到一半發現內存不夠,就尷尬了。
因此問題變爲:

多線程時,如果確保計算的內存量是有效的?

一種方式,就是每次確定要寫入時, 把要寫入的這100M的量直接加到currentMemory中。 後面的線程要判斷時,直接拿最新的curentMemory判斷。
但實際上這個數據並沒有真正寫入map中, 有可能中間出現寫入失敗或者線程中斷, 那這時候已經被處理過的currentMemory就不好搞了。

所以引入一個概念,叫展開內存unrollMemory。
每個線程都有自己的unrollMemory, 可以理解爲該線程 準備 寫入到內存中的大小。
因此我們統計剩餘可寫入內存時, 實際上是等於 MaxMemory - currentMemory - 所有線程unrollMemory總和。

但是我們又不能讓線程展開的這個值正好把剩餘內存佔滿,所以會設定一個展開內存總和maxUnrollMemory,替代MaxMemory。
因此此時我這個線程可用的剩餘內存space,實際上爲
maxUnrollMemory - cyrrentUnrollMemory。
在這裏插入圖片描述

但問題又來了,如果我們假想的可分配內存比實際剩餘內存小,怎麼辦?如下圖:
在這裏插入圖片描述

一種方式,是發現假想剩餘內存小於實際剩餘內存時,認爲內存不足,把數據寫入磁盤。
但有個問題, 假設我需要寫入100M, 實際剩餘內存是98M, 其實只差了2M, 那爲什麼不能擠擠呢?只差2M了啊哥!

然而我肯定不能去動其他線程的unrollMemory,畢竟人家都認爲自己是ok的準備寫入了,你總不能插隊吧?如果能動其他線程準備寫入的數據,這管理就太複雜了。
因此我們需要去已使用內存MemoryEntry裏面找, 找一下是不是有比較小的block塊,比如有一個塊只有5M, 那我就把這個block塊放入磁盤,那麼我就可以塞進去了!

解答完上述問題後,再學習memoryStore的內存寫入管理機制,就容易多了。

memoryStore完整安全展開流程

1. 計算需要寫入的內存大小,是否需要申請新內存

在這裏插入圖片描述
這裏的計算不同於上文中提到的直接遍歷完之後判斷總大小
因爲當時傳入的是一個迭代器,只能迭代一次,每次迭代時都需要放入vector這個臨時存儲的列表中,萬一超級大,放入vector時超出範圍就GG了, 所以它實際時每隔一段就會檢查一下是否超出閾值。

2. 計算剩餘可用的展開空間

在這裏插入圖片描述
spark就是上文提到的這個:
在這裏插入圖片描述
如果小於實際內存,那麼就需要去已分配的內存中找,看下能不能抽一些小朋友去磁盤中。

spark不足時,檢查能否抽一些已分配內存區磁盤

核心方法來自ensureFreeSpace,看下它的實現
在這裏插入圖片描述
這個過程比較簡單,也沒做太多優化,不考慮最優情況,否則會有排序的性能問題。
如果發現抽內存也不夠用, 那就直接認爲不行了。
如果ok,那就認爲可行,
在這裏插入圖片描述

內存足夠分配,寫入

在這裏插入圖片描述
最後會返回一個vector數據
這個vector會拿去做真正的寫入操作。
在這裏插入圖片描述

完整過程:

在這裏插入圖片描述

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