Spark持久化、持久化級別

一、RDD持久化

Spark 中一個很重要的能力是將數據持久化(或稱爲緩存),在多個操作間都可以訪問這些持久化的數據。當持久化一個 RDD 時,每個節點的其它分區都可以使用 RDD 在內存中進行計算,在該數據上的其他 action 操作將直接使用內存中的數據。這樣會讓以後的 action 操作計算速度加快(通常運行速度會加速 10 倍)。緩存是迭代算法和快速的交互式使用的重要工具。

RDD 可以使用 persist() 方法或 cache() 方法進行持久化。數據將會在第一次 action 操作時進行計算,並緩存在節點的內存中。Spark 的緩存具有容錯機制,如果一個緩存的 RDD 的某個分區丟失了,Spark 將按照原來的計算過程,自動重新計算並進行緩存。

在 shuffle 操作中(例如 reduceByKey),即便是用戶沒有調用 persist 方法,Spark 也會自動緩存部分中間數據。這麼做的目的是,在 shuffle 的過程中某個節點運行失敗時,不需要重新計算所有的輸入數據。如果用戶想多次使用某個 RDD,強烈推薦在該 RDD 上調用 persist 方法。

二、Spark有幾種持久化存儲級別如下(參考自博客):

1.MEMORY_ONLY

使用未序列化的Java對象格式,將數據保存在內存中。如果內存不夠存放所有的數據,則數據可能就不會進行持久化。那麼下次對這個RDD執行算子操作時,那些沒有被持久化的數據,需要從源頭處重新計算一遍。這是默認的持久化策略,使用cache()方法時,實際就是使用的這種持久化策略。

2.MEMORY_AND_DISK

使用未序列化的Java對象格式,優先嚐試將數據保存在內存中。如果內存不夠存放所有的數據,會將數據寫入磁盤文件中,下次對這個RDD執行算子時,持久化在磁盤文件中的數據會被讀取出來使用。

3.MEMORY_ONLY_SER

基本含義同MEMORY_ONLY。唯一的區別是,會將RDD中的數據進行序列化,RDD的每個partition會被序列化成一個字節數組。這種方式更加節省內存,從而可以避免持久化的數據佔用過多內存導致頻繁GC。

4.MEMORY_AND_DISK_SER

基本含義同MEMORY_AND_DISK。唯一的區別是,會將RDD中的數據進行序列化,RDD的每個partition會被序列化成一個字節數組。這種方式更加節省內存,從而可以避免持久化的數據佔用過多內存導致頻繁GC。

5.DISK_ONLY

使用未序列化的Java對象格式,將數據全部寫入磁盤文件中。

6.MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等

對於上述任意一種持久化策略,如果加上後綴_2,代表的是將每個持久化的數據,都複製一份副本,並將副本保存到其他節點上。這種基於副本的持久化機制主要用於進行容錯。假如某個節點掛掉,節點的內存或磁盤中的持久化數據丟失了,那麼後續對RDD計算時還可以使用該數據在其他節點上的副本。如果沒有副本的話,就只能將這些數據從源頭處重新計算一遍了。

三、如何選擇存儲級別:(參考自博客)

1、默認情況下,性能最高的當然是MEMORY_ONLY,但前提是你的內存必須足夠足夠大,可以綽綽有餘地存放下整個RDD的所有數據。因爲不進行序列化與反序列化操作,就避免了這部分的性能開銷;對這個RDD的後續算子操作,都是基於純內存中的數據的操作,不需要從磁盤文件中讀取數據,性能也很高;而且不需要複製一份數據副本,並遠程傳送到其他節點上。但是這裏必須要注意的是,在實際的生產環境中,恐怕能夠直接用這種策略的場景還是有限的,如果RDD中數據比較多時(比如幾十億),直接用這種持久化級別,會導致JVM的OOM內存溢出異常。

2、如果使用MEMORY_ONLY級別時發生了內存溢出,那麼建議嘗試使用MEMORY_ONLY_SER級別。該級別會將RDD數據序列化後再保存在內存中,此時每個partition僅僅是一個字節數組而已,大大減少了對象數量,並降低了內存佔用。這種級別比MEMORY_ONLY多出來的性能開銷,主要就是序列化與反序列化的開銷。但是後續算子可以基於純內存進行操作,因此性能總體還是比較高的。此外,可能發生的問題同上,如果RDD中的數據量過多的話,還是可能會導致OOM內存溢出的異常。

3、如果純內存的級別都無法使用,那麼建議使用MEMORY_AND_DISK_SER策略,而不是MEMORY_AND_DISK策略。因爲既然到了這一步,就說明RDD的數據量很大,內存無法完全放下。序列化後的數據比較少,可以節省內存和磁盤的空間開銷。同時該策略會優先儘量嘗試將數據緩存在內存中,內存緩存不下才會寫入磁盤。(除了在計算該數據集的代價特別高,或者在需要過濾大量數據的情況下,儘量不要將溢出的數據存儲到磁盤。因爲,重新計算這個數據分區的耗時與從磁盤讀取這些數據的耗時差不多。)

4、通常不建議使用DISK_ONLY和後綴爲_2的級別:因爲完全基於磁盤文件進行數據的讀寫,會導致性能急劇降低,有時還不如重新計算一次所有RDD。後綴爲_2的級別,必須將所有數據都複製一份副本,併發送到其他節點上,數據複製以及網絡傳輸會導致較大的性能開銷,除非是要求作業的高可用性,否則不建議使用。

四、cache和persist的區別

cache()調用了persist()

cache只有一個默認的緩存級別MEMORY_ONLY ,而persist可以根據情況設置其它的緩存級別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章