Spark 做爲一個以擅長內存計算爲優點的計算引擎,內存管理方案是其很是重要的模塊; Spark的內存能夠大致歸爲兩類:execution和storage,前者包括shuffles、joins、sorts和aggregations所需內存,後者包括cache和節點間數據傳輸所需內存;在Spark 1.5和以前版本里,二者是靜態配置的,不支持借用,spark1.6 對內存管理模塊進行了優化,經過內存空間的融合,消除以上限制,提供更好的性能。官方網站只是要求內存在8GB之上便可(Impala推薦要求機器配置在128GB), 但spark job運行效率主要取決於:數據量大小,內存消耗,內核數(肯定併發運行的task數量)git
目錄:github
- 基礎知識
- spark1.5- 內存管理
- spark1.6 內存管理
基本知識:算法
- on-heap memory:Java中分配的非空對象都是由Java虛擬機的垃圾收集器管理的,也稱爲堆內內存。虛擬機會按期對垃圾內存進行回收,在某些特定的時間點,它會進行一次完全的回收(full gc)。完全回收時,垃圾收集器會對全部分配的堆內內存進行完整的掃描,這意味着一個重要的事實——這樣一次垃圾收集對Java應用形成的影響,跟堆的大小是成正比的。過大的堆會影響Java應用的性能
- off-heap memory:堆外內存意味着把內存對象分配在Java虛擬機的堆之外的內存,這些內存直接受操做系統管理(而不是虛擬機)。這樣作的結果就是能保持一個較小的堆,以減小垃圾收集對應用的影響
- LRU Cache(Least Recently Used):LRU能夠說是一種算法,也能夠算是一種原則,用來判斷如何從Cache中清除對象,而LRU就是「近期最少使用」原則,當Cache溢出時,最近最少使用的對象將被從Cache中清除
- spark 源碼: https://github.com/apache/spark/releases
- scale ide for Intellij : http://plugins.jetbrains.com/plugin/?id=1347
Spark1.5- 內存管理:apache
- 1.6 版本引入了新的內存管理方案,配置參數: spark.memory.useLegacyMode 默認 false 表示使用新方案,true 表示使用舊方案, SparkEnv.scala 源碼 以下圖:

- 在staticMemoryManager.scala 類中查看構造類及內存獲取定義

- 經過代碼推斷,若設置了 spark.testing.memory 則以該配置的值做爲 systemMaxMemory,不然使用 JVM 最大內存做爲 systemMaxMemory。
- spark.testing.memory 僅用於測試,通常不設置,因此這裏咱們認爲 systemMaxMemory 的值就是 executor 的最大可用內存
- Execution:用於緩存shuffle、join、sort和aggregation的臨時數據,經過spark.shuffle.memoryFraction配置
- spark.shuffle.memoryFraction:shuffle 期間佔 executor 運行時內存的百分比,用小數表示。在任什麼時候候,用於 shuffle 的內存總 size 不得超過這個限制,超出部分會 spill 到磁盤。若是常常 spill,考慮調大參數值
- spark.shuffle.safetyFraction:爲防止 OOM,不能把 systemMaxMemory * spark.shuffle.memoryFraction 全用了,須要有個安全百分比
- 最終用於 execution 的內存量爲:executor 最大可用內存* spark.shuffle.memoryFraction*spark.shuffle.safetyFraction,默認爲 executor 最大可用內存 * 0.16
- execution內存被分配給JVM裏的多個task線程。
- task間的execution內存分配是動態的,若是沒有其餘tasks存在,Spark容許一個task佔用全部可用execution內存
- storage內存分配分析過程與 Execution 一致,由上面的代碼得出,用於storage 的內存量爲: executor 最大可用內存 * spark.storage.memoryFraction * spark.storage.safetyFraction,默認爲 executor 最大可用內存 * 0.54
- 在 storage 中,有一部份內存是給 unroll 使用的,unroll 即反序列化 block,該部分佔比由 spark.storage.unrollFraction 控制,默認爲0.2
- 經過代碼分析,storage 和 execution 總共使用了 80% 的內存,剩餘 20% 內存被系統保留了,用來存儲運行中產生的對象,該類型內存不可控.
小結:緩存
- 這種內存管理方式的缺陷,即 execution 和 storage 內存表態分配,即便在一方內存不夠用而另外一方內存空閒的狀況下也不能共享,形成內存浪費,爲解決這一問題,spark1.6 啓用新的內存管理方案UnifiedMemoryManager
- staticMemoryManager- jvm 堆內存分配圖以下

Spark1.6 內存管理:安全
-
- 一方空閒,一方內存不足狀況下,內存不足一方能夠向空閒一方借用內存
- 只有Execution Memory能夠強制拿回Storage Memory在Execution Memory空閒時,借用的Execution Memory的部份內存(若是因強制取回,而Storage Memory數據丟失,從新計算便可)
- 若是Storage Memory只能等待Execution Memory主動釋放佔用的Storage Memory空閒時的內存。(這裏不強制取回,由於若是task執行,數據丟失就會致使task 失敗)