• 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的级别,必须将所有数据都复制一份副本,并发送到其他节点上,数据复制以及网络传输会导致较大的性能开销,除非是要求作业的高可用性,否则不建议使用。
  • 相关阅读:
    宽带上网路由器设置
    ssh 与 irc
    Centos7 wifi
    linux无法挂载u盘
    virtualbox之usb设备的分配
    5G工程师必备!5G协议清单大全
    SSB的时频资源怎么确定的?UE那边怎么检测呢?
    link
    C++有用link
    C++学习路线转载
  • 原文地址:https://www.cnblogs.com/weiyiming007/p/11150913.html
Copyright © 2020-2023  润新知