Spark RDD 持久化
注:該文檔針對Spark2.1.0版本
Spark最重要的一個功能是它可以通過各種操作(operations)持久化(或者緩存)一個集合到記憶體中。當你持久化一個RDD的時候,每一個節點都将參與計算的所有分區資料存儲到記憶體中,并且這些資料可以被這個集合(以及這個集合衍生的其他集合)的動作(action)重複利用。這個能力使後續的動作速度更快(通常快10倍以上)。對應疊代算法和快速的互動使用來說,緩存是一個關鍵的工具。
你能通過
persist()
或者
cache()
方法持久化一個rdd。首先,在action中計算得到rdd;然後,将其儲存在每個節點的記憶體中。Spark的緩存是一個容錯的技術-如果RDD的任何一個分區丢失,它可以通過原有的轉換(transformations)操作自動的重複計算并且建立出這個分區。
此外,每個持久化的RDD可以使用不同的存儲級别存儲,例如,允許您在磁盤上持久化資料集,将其儲存在記憶體中,但作為序列化的Java對象(為了節省空間),可以跨節點複制它。這些級别通過傳遞一個StorageLevel對象(Scala、Java、Python)來持久化()。cache()方法是使用預設存儲級别的縮寫,它是StorageLevel。MEMORY_ONLY(存儲在記憶體中的反序列化對象)。完整的存儲級别為:
存儲級别 | 解釋 |
---|---|
MEMORY_ONLY | 将RDD作為非序列化的Java對象存儲在jvm中。如果RDD不适合存在記憶體中,一些分區将不會被緩存,進而在每次需要這些分區時都需重新計算它們。這是系統預設的存儲級别。 |
MEMORY_AND_DISK | 以反序列化的JAVA對象的方式存儲在JVM中. 如果記憶體不夠, RDD的一些分區将将會緩存在磁盤上,再次需要的時候從磁盤讀取 |
MEMORY_ONLY_SER | 以序列化JAVA對象的方式存儲 (每個分區一個位元組數組). 相比于反序列化的方式,這樣更高效的利用空間, 尤其是使用快速序列化時。但是讀取是CPU操作很密集。 |
MEMORY_AND_DISK_SER | 與MEMORY_ONLY_SER相似, 差別是但記憶體不足時,存儲在磁盤上而不是每次重新計算 |
DISK_ONLY | 隻存儲RDD在磁盤 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2, etc. | 與上面的級别相同,隻不過每個分區的副本隻存儲在兩個叢集節點上。 |
OFF_HEAP (experimental) | 與MEMORY_ONLY_SER類似,但将資料存儲在非堆記憶體中。這需要啟用非堆記憶體。 |
注:在python裡,通過Pickle庫來存儲對象總是以序列化的方式,與存儲級别中的序列化标志無關。
Spark也自動地持久化一些中間資料在shuffle操作中,盡管使用者沒有調用persist.這樣做是為了避免重新計算整個輸入當一個節點失敗時。我們建議使用者對結果RDD調用persist,如果計劃重複使用它們。
存儲級别的選擇
Spark的存儲級别是為了提供記憶體使用率和CPU效率的均衡。我們建議您通過以下方式來選擇:
- 如果你的RDD在預設的存儲級别下工作的很好,就不要用其它的級别。這是最有CPU效率的選項,允許RDD上的操作盡快的完成。
- 如果不行,試下MEMORY_ONLY_SER并使用一個能快速序列化的庫,這樣更節省空間,同時通路速度也比較快。
- 不要存儲資料到磁盤,除非在資料集上的計算操作是昂貴的,或者過濾了大量的資料。否則重新計算可能比從磁盤中讀取更快
- 使用備份級别,如果你需要更快的恢複。(比如,使用Spark為網絡應用程式提供服務)。所有的存儲級别都通過重新計算提供了全面的容錯性,但是備份級别允許你繼續在RDD上執行任務而無需重新計算丢失的分區。
移除持久化
Spark自動地監控每個節點上的緩存使用率。并通過LRU算法删除過時的資料。如果你想手動删除一個RDD而不是等待它從緩存中過時,可以使用RDD.unpersist方法。
參考文檔
http://spark.apache.org/docs/2.1.0/programming-guide.html#rdd-persistence