Spark RDD Persistence

Spark最爲重要的特性之一就是能夠在多個操做(Action)之間,將一個或多個RDD關聯的數據集(Dataset)以分區(Partition)爲單位進行持久化(Persist)或緩存(Cache),存儲介質一般是內存(Memory)。
 
被持久化或緩存的RDD A能夠在兩種狀況下被很好地「重複」利用:
 
(1)直接依賴:操做(Action)直接應用於RDD A之上;
(2)間接依賴:操做(Action)間接應用於RDD B之上,而RDD B來源於RDD A;
 
持久化或緩存是迭代式計算和交互式應用的關鍵技術,一般能夠提高10位以上的計算速度。
 
實際應用中,RDD的持久化或緩存選項是經過persist()或cache()發出的,以後若是某個操做(Action)觸發該RDD的數據第一次被計算,那麼計算的結果數據(也就是該RDD的數據)就會以分區的形式被緩存於計算節點的內存中;並且這些數據是能夠實現容錯的,若是這個RDD的某些分區數據丟失(由於節點故障),這些分區的數據能夠在使用時經過世代信息(Lineage)被自動恢復。
 
RDD的存儲形式或存儲介質是能夠經過存儲級別(Storage Level)被定義的。例如,將數據持久化到磁盤、將Java對象序列化以後(有利於節省空間)緩存至內存、開啓複製(RDD的分區數據能夠被備份到多個節點防止丟失)或者使用堆外內存(Tachyon)。persist()能夠接收一個StorageLevel對象(Scala、Java、Python)用以定義存儲級別,若是使用的是默認的存儲級別(StorageLevel.MEMORY_ONLY),Spark提供了一個便利方法:cache()。
 
存儲級別選項以下:
 
 
MEMORY_ONLY 默認選項,RDD的(分區)數據直接以Java對象的形式存儲於JVM的內存中,若是內存空間不足,某些分區的數據將不會被緩存,須要在使用的時候根據世代信息從新計算。
MYMORY_AND_DISK RDD的數據直接以Java對象的形式存儲於JVM的內存中,若是內存空間不中,某些分區的數據會被存儲至磁盤,使用的時候從磁盤讀取。
MEMORY_ONLY_SER RDD的數據(Java對象)序列化以後存儲於JVM的內存中(一個分區的數據爲內存中的一個字節數組),相比於MEMORY_ONLY可以有效節約內存空間(特別是使用一個快速序列化工具的狀況下),但讀取數據時須要更多的CPU開銷;若是內存空間不足,處理方式與MEMORY_ONLY相同。
MEMORY_AND_DISK_SER 相比於MEMORY_ONLY_SER,在內存空間不足的狀況下,將序列化以後的數據存儲於磁盤。
DISK_ONLY 僅僅使用磁盤存儲RDD的數據(未經序列化)。
MEMORY_ONLY_2,
MEMORY_AND_DISK_2, etc.
以MEMORY_ONLY_2爲例,MEMORY_ONLY_2相比於MEMORY_ONLY存儲數據的方式是相同的,不一樣的是會將數據備份到集羣中兩個不一樣的節點,其他狀況相似。
OFF_HEAP(experimental) RDD的數據序例化以後存儲至Tachyon。相比於MEMORY_ONLY_SER,OFF_HEAP可以減小垃圾回收開銷、使得Spark Executor更「小」更「輕」的同時能夠共享內存;並且數據存儲於Tachyon中,Spark集羣節點故障並不會形成數據丟失,所以這種方式在「大」內存或多併發應用的場景下是頗有吸引力的。須要注意的是,Tachyon並不直接包含於Spark的體系以內,須要選擇合適的版本進行部署;它的數據是以「塊」爲單位進行管理的,這些塊能夠根據必定的算法被丟棄,且不會被重建。
 
注意:使用PySpark(即便用Python開發Spark應用程序)時,全部須要存儲的數據都會使用Pickle進行序列化,這種行爲與存儲級別無關。
 
Spark推薦用戶將須要重複使用的RDD經過persist()或cache()顯式持久化。同時咱們須要知道,會觸發「Shuffle」的操做是特殊的,例如reduceByKey,即便沒有用戶的顯式persist,它也會自動持久化「Shuffle」的中間結果,以防止「Shuffle」過程當中某些節點故障致使整個輸入數據被從新計算。
 
那麼咱們應該如何選取持久化的存儲級別呢?實際上存儲級別的選取就是Memory與CPU之間的雙重權衡,能夠參考下述內容:
 
(1)若是RDD的數據能夠很好的兼容默認存儲級別(MEMORY_ONLY),那麼優先使用它,這是CPU工做最爲高效的一種方式,能夠很好地提升運行速度;
 
(2)若是(1)不能知足,則嘗試使用MEMORY_ONLY_SER,且選擇一種快速的序列化工具,也能夠達到一種不錯的效果;
 
(3)通常狀況下不要把數據持久化到磁盤,除非計算是很是「昂貴」的或者計算過程會過濾掉大量數據,由於從新計算一個分區數據的速度可能要高於從磁盤讀取一個分區數據的速度;
 
(4)若是須要快速的失敗恢復機制,則使用備份的存儲級別,如MEMORY_ONLY_二、MEMORY_AND_DISK_2;雖然全部的存儲級別均可以經過從新計算丟失的數據實現容錯,可是備份機制使得大部分狀況下應用無需中斷,即數據丟失狀況下,直接使用備份數據,而不須要從新計算數據的過程;
 
(5)若是處於大內存或多應用的場景下,OFF_HEAP能夠帶來如下的好處:
 
     a. 它容許Spark Executors能夠共享Tachyon的內存數據;
     b. 它很大程序上減小JVM垃圾回收帶來的性能開銷;
     c. Spark Executors故障不會致使數據丟失。
 
最後,Spark能夠本身監測「緩存」空間的使用,並使用LRU算法移除舊的分區數據。咱們也能夠經過顯式調用RDD unpersist()手動移除數據。
相關文章
相關標籤/搜索