8、RDD持久化


一、RDD持久化

1、不使用RDD持久化的問題

image

 

2、RDD持久化原理

Spark非常重要的一個功能特性就是可以將RDD持久化在內存中。當對RDD執行持久化操作時,每個節點都會將自己操作的RDD的partition持久化到內存中,並且在之后對
該RDD的反復使用中,直接使用內存緩存的partition。這樣的話,對於針對一個RDD反復執行多個操作的場景,就只要對RDD計算一次即可,后面直接使用該RDD,而不
需要反復計算多次該RDD。

巧妙使用RDD持久化,甚至在某些場景下,可以將spark應用程序的性能提升10倍。對於迭代式算法和快速交互式應用來說,RDD持久化,是非常重要的。

要持久化一個RDD,只要調用其cache()或者persist()方法即可。在該RDD第一次被計算出來時,就會直接緩存在每個節點中。而且Spark的持久化機制還是自動容錯的,
如果持久化的RDD的任何partition丟失了,那么Spark會自動通過其源RDD,使用transformation操作重新計算該partition。

cache()和persist()的區別在於,cache()是persist()的一種簡化方式,cache()的底層就是調用的persist()的無參版本,同時就是調用persist(MEMORY_ONLY),將數據持久化到內存
中。如果需要從內存中清楚緩存,那么可以使用unpersist()方法。

Spark自己也會在shuffle操作時,進行數據的持久化,比如寫入磁盤,主要是為了在節點失敗時,避免需要重新計算整個過程。

 

image

 

3、RDD持久化

------java實現--------

package cn.spark.study.core;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;

/**
 * RDD持久化
 * @author Administrator
 *
 */
public class Persist {

    public static void main(String[] args) {
        SparkConf conf = new SparkConf()
                .setAppName("Persist")
                .setMaster("local"); 
        JavaSparkContext sc = new JavaSparkContext(conf);
        
        // cache()或者persist()的使用,是有規則的
        // 必須在transformation或者textFile等創建了一個RDD之后,直接連續調用cache()或persist()才可以
        // 如果你先創建一個RDD,然后單獨另起一行執行cache()或persist()方法,是沒有用的
        // 而且,會報錯,大量的文件會丟失
        JavaRDD<String> lines = sc.textFile("D://test-file//spark.txt").cache();
        
        long beginTime = System.currentTimeMillis();
        
        long count = lines.count();
        System.out.println(count);  
        
        long endTime = System.currentTimeMillis();
        System.out.println("cost " + (endTime - beginTime) + " milliseconds.");   
        
        beginTime = System.currentTimeMillis();
        
        count = lines.count();
        System.out.println(count);  
        
        endTime = System.currentTimeMillis();
        System.out.println("cost " + (endTime - beginTime) + " milliseconds.");
        
        sc.close();
    }
    
}

 

4、RDD持久化策略

RDD持久化是可以手動選擇不同的策略的。比如可以將RDD持久化在內存中、持久化到磁盤上、使用序列化的方式持久化,多持久化的數據進行多路復用。
只要在調用persist()時傳入對應的StorageLevel即可。

 

 

5、如何選擇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的級別,必須將所有數據都復制一份副本,並發送到其他節點上,數據復制以及網絡傳輸會導致較大的性能開銷,除非是要求作業的高可用性,否則不建議使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM