轉載:http://www.cnblogs.com/jcchoiling/p/6494652.htmlhtml
Spark 從1.6.x 開始對 JVM 的內存使用做出了一種全新的改變,Spark 1.6.x 之前是基於靜態固定的JVM內存使用架構和運行機制,若是你不知道 Spark 到底對 JVM 是怎麼使用,你怎麼能夠頗有信心地或者是徹底肯定地掌握和控制數據的緩存空間呢,因此掌握Spark對JVM的內存使用內幕是相當重要的。不少人對 Spark 的印象是:它是基於內存的,並且能夠緩存一大堆數據,顯現 Spark 是基於內存的觀點是錯的,Spark 只是優先充分地利用內存而已。若是你不知道 Spark 能夠緩存多少數據,你就誤亂地緩存數據的話,確定會有問題。算法
在數據規模已經肯定的狀況下,你有多少 Executor 和每一個 Executor 可分配多少內存 (在這個物理硬件已經肯定的狀況下),你必須清楚知道你的內存最多可以緩存多少數據;在 Shuffle 的過程當中又使用了多少比例的緩存,這樣對於算法的編寫以及業務實現是相當重要的!!!緩存
文章的後部份會介紹 Spark 2.x 版本 JVM 的內存使用比例,它被稱之爲 Spark Unified Memory,這是統一或者聯合的意思,可是 Spark 沒有用 Shared 這個字,由於 A 和 B 進行 Unified 和 A 和 B 進行 Shared 實際上是兩個不一樣的概念, Spark 在運行的時候會有不一樣類型的 OOM,你必須搞清楚這個 OOM 背後是由什麼致使的。 好比說咱們使用算子 mapPartition 的時候,通常會建立一些臨時對象或者是中間數據,你這個時候使用的臨時對象和中間數據,是存儲在一個叫 UserSpace 裏面的用戶操做空間,那你有沒有想過這個空間的大小會致使應用程序出現 OOM 的狀況,在 Spark 2.x 中 Broadcast 的數據是存儲在什麼地方;ShuffleMapTask 的數據又存儲在什麼地方,可能你會認爲 ShuffleMapTask 的數據是緩存在 Cache 中。這篇文章會介紹 JVM 在 Spark 1.6.X 之前和 2.X 版本對 Java 堆的使用,還會逐一解密上述幾個疑問,也會簡單介紹 Spark 1.6.x 之前版本在 Spark On Yarn 上內存的使用案例,但願這篇文章能爲讀者帶出如下的啓發: 安全
JVM 有不少不一樣的區,最開始的時候,它會經過類裝載器把類加載進來,在運行期數據區中有 "本地方法棧","程序計數器","Java 棧"、"Java 堆"和"方法區"以及本地方法接口和它的本地庫。從 Spark 的角度來談代碼的運行和數據的處理,主要是談 Java 堆 (Heap) 空間的運用。架構
一、Spark JVM 到底能夠緩存多少數據併發
下圖顯示的是Spark 1.6.x 之前版本對 Java 堆 (heap) 的使用狀況,左則是 Storage 對內存的使用,右則是 Shuffle 對內存的使用,這叫 StaticMemoryManagement,數據處理以及類的實體對象都存放在 JVM 堆 (heap) 中。spa
二、Spark 1.6.x 版本對 JVM 堆的使用線程
JVM Heap 默認狀況下是 512MB,這是取決於 spark.executor.memory 的參數,在回答 Spark JVM 到底能夠緩存多少數據這個問題以前,首先了解一下 JVM Heap 在 Spark 中是如何分配內存比例的。不管你定義了 spark.executor.memory 的內存空間有多大,Spark 必然會定義一個安全空間,在默認狀況下只會使用 Java 堆上的 90% 做爲安全空間,在單個 Executor 的角度來說,就是 Heap Size x 90%。htm
埸景一:假設說在一個Executor,它可用的 Java Heap 大小是 10G,實際上 Spark 只能使用 90%,這個安全空間的比例是由 spark.storage.safetyFaction 來控制的。(若是你內存的 Heap 很是大的話,能夠嘗試調高爲 95%),在安全空間中也會劃分三個不一樣的空間:一個是 Storage 空間、一個是 Unroll 空間和一個是 Shuffle 空間。對象
安全空間 (safe):計算公式是 spark.executor.memory x spark.storage.safetyFraction。也就是 Heap Size x 90%,在埸景一的例子中是 10 x 0.9 = 9G;
緩存空間 (Storage):計算公式是 spark.executor.memory x spark.storage.safetyFraction x spark.storage.memoryFraction。也就是 Heap Size x 90% x 60%;Heap Size x 54%,在埸景一的例子中是 10 x 0.9 x 0.6 = 5.4G;一個應用程序能夠緩存多少數據是由 safetyFraction 和 memoryFraction 這兩個參數共同決定的。
Unroll 空間:
計算公式是 spark.executor.memory x spark.storage.safetyFraction x spark.storage.memoryFraction x spark.storage.unrollFraction
也就是 Heap Size x 90% x 60% x 20%;Heap Size x 10.8%,在埸景一的例子中是 10 x 0.9 x 0.6 x 0.2 = 1.8G,你可能把序例化後的數據放在內存中,當你使用數據時,你須要把序例化的數據進行反序例化。
對 cache 緩存數據的影響是因爲 Unroll 是一個優先級較高的操做,進行 Unroll 操做的時候會佔用 cache 的空間,並且又能夠擠掉緩存在內存中的數據 (若是該數據的緩存級別是 MEMORY_ONLY 的話,不然該數據會丟失)。
Shuffle 空間:
計算公式是 spark.executor.memory x spark.shuffle.memoryFraction x spark.shuffle.safteyFraction。在 Shuffle 空間中也會有一個默認 80% 的安全空間比例,因此應該是 Heap Size x 20% x 80%;Heap Size x 16%,在埸景一的例子中是 10 x 0.2 x 0.8 = 1.6G;從內存的角度講,你須要從遠程抓取數據,抓取數據是一個 Shuffle 的過程,好比說你須要對數據進行排序,顯如今這個過程當中須要內存空間。
下圖是一種叫聯合內存 (Spark Unified Memeory),數據緩存與數據執行之間的內存能夠相互移動,這是一種更彈性的方式,下圖顯示的是 Spark 2.x 版本對 Java 堆 (heap) 的使用狀況,數據處理以及類的實體對象存放在 JVM 堆 (heap) 中。