Spark內存管理(譯)

原文地址: https://0x0fff.com/spark-memory-management/

從Apache Spark 1.6開始,內存管理模型就發生了變化了。以前的內存管理模型是通過StaticMemoryManager 實現的,而現在,默認情況下,并不會使用這個內存管理模型。也就是說,即使你在Spark 1.5.x和Spark 1.6.0上運行相同的代碼,結果也會是不同的。這一點要特別小心。

當然,你還是可以手動啟用舊的內存管理模型的。只需要指定這么一個參數spark.memory.useLegacyMode

前面的文章中,我已經描述過舊的Spark內存管理模型(譯者注:譯者同樣翻譯過這篇文章,鏈接為Spark架構)。而且,還寫了Spark Shuffle implementations這篇文章,來簡單描述不同的shuffle策略對內存的使用。

而在這篇文章中,我們會描述Spark 1.6.0中出現的新的內存管理模型。它是通過UnifiedMemoryManager實現的。

簡而言之,新的內存管理模型,如下所示:


在上圖中,我們會看到,總共有三個區域:

  • Reserved Memory。如名字所示,這塊內存是留給系統使用的。它的大小是硬編碼的,我們無法改變它的大小,除非重新編譯源代碼,或者使用spark.testing.reservedMemory這個配置,而毫無疑問,后者是我們不推薦使用的,畢竟只是一個測使用的配置項。
    在Spark 1.6.0中,它的大小是300MB,也就是說,我們分配的堆內存中的300MB,在我們計算程序可用內存時,不應該計算在內。你不可能用全部的堆內存來緩沖數據,因為這塊內存的存在。當然這塊內存也不是劃分出來,啥事都不做。它會保存很多Spark的內部使用到的對象。
    在給Spark executor設置堆內存時,如果你分配的堆內存小于1.5 * Reserved Memory=450MB,那么,會直接甩你一個please use larger heap size然后轉身離開。
  • User Memory。這塊內存,如名字所示,完全取決于用戶。你可以用它存儲一些你在RDD transformation中用到的數據結構。舉個栗子,如果你想寫通過使用mapPartitions實現一個聚集函數,并且內部維護一個Hash表,那么,這個Hash表就會被存儲在User Memory中。
    在Spark 1.6.0中,這塊內存的大小,可以通過(Java Heap – Reserved Memory) * (1.0 – spark.memory.fraction)計算得出,也就是說,默認情況下,是(Java Heap – 300MB) * 0.25。如果我們給executor分配了4GB的堆內存,那么,User Memory將是949MB。
    再重申一遍,這塊內存,怎么使用,完全取決于用戶。Spark不會幫你監管它。所以,如果你不清楚你的User Memory的大小,而存儲了一個比它大的對象,那么,很可能會導致OOM。
  • Spark Memory。這塊內存是Spark管理的內存,它的大小是(Java Heap – Reserved Memory) * spark.memory.fraction,默認情況下,是(Java Heap – 300MB) * 0.75。如果我們給Executor分配4GB的堆內存,那么,這塊內存有2847MB。
    整個Spark Memory被分成兩部分,Storage Memory和Execution Memory。這兩者,各占大小,通過spark.memory.storageFraction這個參數來配置,默認情況,是0.5,也就是五五開。
    在新的內存管理模型下,Storage Memory和Execution Memory的大小并不是固定的。

我們下面介紹Storage Memory和Execution Memory是如何被使用的:

  1. Storage Memory。這塊內存會被Spark用來緩存數據,以及臨時存放序列化過的數據。全部的broadcast變量,都會作為緩存,存儲在這塊區域中。如果你感興趣,可以讀一下這份代碼unroll。你可能會看到,對于unrolled block,如果內存不夠,沒關系,只要persistence level允許,它會直接把unrolled partition放到硬盤里。全部的broadcast變量,會以MEMORY_AND_DISK的persistence level,存放在緩存中。
  2. Execution Memory.這塊內存,Spark會用來存儲執行Task時產生的對象。例如,它會存儲Shuffle時,Map端產生的中間對象(譯者疑問:那Reducer端存放在哪兒呢?前幾天就是Shuffle時Reducer內存爆掉了),它也會存儲Hash Aggregation時,內部需要用到的HashTable。當內存不足時,會自動刷到磁盤上。但是,其它的線程(Task),不能強制收回內存。

好,接下來我們介紹Storage Memory and Execution Memory之間的內存重新分配問題。

從上面對Execution Memory的介紹中,我們可以看到,我們不能強制回收Execution Memory中的內存。因為Execution Memory中存儲的,都是運行Task時需要的對象,如果回收掉,那么Task就不能正常運行了。但是Storage Memory就不一樣了,它只是緩存,即使我們回收了這些內存,我們只需要簡單的更新元數據,告訴它這塊內存被刷到磁盤上或者已經被移除掉了,然后當我們再次訪問這些緩存數據時,Spark會直接從磁盤上讀(如果persistence level不允許刷到磁盤上,那么會重新計算。)

所以,我們完全可以回收掉Storage Memory,將它們劃給Execution Meomry使用。那到底在什么情況下,Execution Memory可以使用Storage Memory呢?

只要發生下面兩種情況中的一個即可:

  • Storage Memory中有空閑的內存。比如說,緩存的數據并沒有用了Storage Memory中全部的內存。那我們就可以將剩下的給Execution Memory使用。
  • Storage Memory超過了剛開始給它分配的大小,并且這些內存全部被使用了。當發生這種情況時,current storage memroy size - intial storage memory size這些內存,都會被強制刷到磁盤上。

而與此相反,只有當Execution Memory有空閑的時,Storage Memory才能使用。

Initial Storage Memory size,可以通過下面的公式計算Spark Memory * spark.memory.fraction * spark.memory.storageFraction = (Java Heap – Reserved Memory) * spark.memory.fraction * spark.memory.storageFraction(譯者注,原文這里少了spark.memory.fraction)。在默認情況下,是(Java Heap – 300MB) * 0.75 * 0.5 = (Java Heap – 300MB) * 0.375。如果Executor的堆內存有4GB,那Initial Storage Memory size是1423.5MB

所以,如果你要放到Storage Memory中的緩存的大小,要跟initial Storage Memory size一樣大,甚至比它還大。而Execution Memory使用的內存,比Execution Memory的initial size還大,并且,此時Execution Memory已經壓榨了Storage Memory的內存,使它不能放下全部的緩存。那么,Execution Memory并不會說,"抱歉,我騰出來點給你吧"。而是直接就一把掌,"滾犢子"。Storage Memory就只能委屈的用此時僅有的那點內存,只有當Execution Memory主動釋放了一部分內存以后,它才能占用。

后記

原文中,有很多有價值的提問,所以建議還是讀原文。并附帶看一下提問。

其他鏈接

Spark內存管理詳解
[Spark性能調優] Spark Shuffle 中 JVM 內存使用及配置內幕詳情
Spark study notes: core concepts visualized

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容