spark記憶體管理這一篇就夠了

skaarl發表於2020-11-13

1. 堆內和堆外記憶體規劃

1.1 堆內記憶體

堆內記憶體的大小,由 Spark 應用程式啟動時的 –executor-memory 或 spark.executor.memory 引數配置。Executor 內執行的併發任務共享 JVM 堆內記憶體,這些任務在快取 RDD 資料和廣播(Broadcast)資料時佔用的記憶體被規劃為儲存(Storage)記憶體,而這些任務在執行 Shuffle 時佔用的記憶體被規劃為執行(Execution)記憶體,剩餘的部分不做特殊規劃,那些 Spark 內部的物件例項,或者使用者定義的 Spark 應用程式中的物件例項,均佔用剩餘的空間。不同的管理模式下,這三部分佔用的空間大小各不相同。

1.2 堆外記憶體

在預設情況下堆外記憶體並不啟用,可通過配置 spark.memory.offHeap.enabled 引數啟用,並由 spark.memory.offHeap.size 引數設定堆外空間的大小。除了沒有 other 空間,堆外記憶體與堆內記憶體的劃分方式相同,所有執行中的併發任務共享儲存記憶體和執行記憶體。

2 . 記憶體空間分配

2.1 統一記憶體管理

Spark 1.6 之後引入的統一記憶體管理機制,與靜態記憶體管理的區別在於儲存記憶體和執行記憶體共享同一塊空間,可以動態佔用對方的空閒區域,如圖 4 和圖 5 所示

圖 4 . 統一記憶體管理圖示——堆內

spark.memory.fraction       堆內的儲存記憶體和執行記憶體總共所佔的比例,預設0.6

spark.storage.storageFraction     用於快取資料的記憶體比例,預設0.5

圖 5 . 統一記憶體管理圖示——堆外

spark.memory.storageFraction         Storage記憶體所佔堆外記憶體的比例,預設為0.5

其中最重要的優化在於動態佔用機制,其規則如下:

  • 設定基本的儲存記憶體和執行記憶體區域(spark.storage.storageFraction 引數),該設定確定了雙方各自擁有的空間的範圍
  • 雙方的空間都不足時,則儲存到硬碟;若己方空間不足而對方空餘時,可借用對方的空間;(儲存空間不足是指不足以放下一個完整的 Block)
  • 執行記憶體的空間被對方佔用後,可讓對方將佔用的部分轉存到硬碟,然後"歸還"借用的空間(執行記憶體的強勢)
  • 儲存記憶體的空間被對方佔用後,無法讓對方"歸還",因為需要考慮 Shuffle 過程中的很多因素,實現起來較為複雜

圖 6 . 動態佔用機制圖示

憑藉統一記憶體管理機制,Spark 在一定程度上提高了堆內和堆外記憶體資源的利用率,降低了開發者維護 Spark 記憶體的難度,但並不意味著開發者可以高枕無憂。譬如,所以如果儲存記憶體的空間太大或者說快取的資料過多,反而會導致頻繁的全量垃圾回收,降低任務執行時的效能,因為快取的 RDD 資料通常都是長期駐留記憶體的 。所以要想充分發揮 Spark 的效能,需要開發者進一步瞭解儲存記憶體和執行記憶體各自的管理方式和實現原理。

相關文章