• Spark学习 RDD 概述


    spark 为了达到高并发,高吞吐数据处理能力封装了三大数据对象;
    • RDD 弹性分布式数据集
    • 累加器:分布式共享只写变量
    • 广播变量:分布式共享只读变量

    1、RDD 概述

    1.1、RDD 引入之IO流

    首先回顾下java 中IO的设计模式
    IO流和RDD之间的关系

    1.2、什么是RDD

    RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象。代码中是一个抽象类,它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。
    弹性
      存储的弹性:内存与磁盘的自动切换;
      容错的弹性:数据丢失可以自动恢复;
      计算的弹性:计算出错重试机制;
      分片的弹性:可根据需要重新分片。
    分布式
           数据存储在大数据集群不同节点上
    数据集
      RDD封装了计算逻辑,并不保存数据
    数据抽象
      RDD是一个抽象类,需要子类具体实现
    不可变
      RDD封装了计算逻辑,是不可以改变的,想要改变,只能产生新的RDD,在新的RDD里面封装计算逻辑
    可分区、并行计算

    1.3、RDD 核心属性

     * Internally, each RDD is characterized by five main properties:
     *
     *  - A list of partitions
     *  - A function for computing each split
     *  - A list of dependencies on other RDDs
     *  - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
     *  - Optionally, a list of preferred locations to compute each split on (e.g. block locations for
     *    an HDFS file)

    1、分区列表 RDD 数据结构存放在分区列表中,用于实现并行计算,是分布式计算的基础属性;

     /**
       * Implemented by subclasses to return the set of partitions in this RDD. This method will only
       * be called once, so it is safe to implement a time-consuming computation in it.
       *
       * The partitions in this array must satisfy the following property:
       *   `rdd.partitions.zipWithIndex.forall { case (partition, index) => partition.index == index }`
       */
      protected def getPartitions: Array[Partition]

    2、分区计算函数,spark 在计算时,使用分区计算函数对每一个分区进行计算

    /**
     * :: DeveloperApi ::
     * Implemented by subclasses to compute a given partition.
     */
    @DeveloperApi
    def compute(split: Partition, context: TaskContext): Iterator[T]
    3、RDD 之间依赖关系 当计算需要多个计算模型时组合时,需要依赖关系将多个RDD建立依赖关系; 
    /**
     * Implemented by subclasses to return how this RDD depends on parent RDDs. This method will only
     * be called once, so it is safe to implement a time-consuming computation in it.
     */
    protected def getDependencies: Seq[Dependency[_]] = deps
    4、分区器 可选,当数据为 KV 数据时,可以设定分区自定义分区 
    /**
     * Optionally overridden by subclasses to specify placement preferences.
     */
    protected def getPreferredLocations(split: Partition): Seq[String] = Nil
    
    /** Optionally overridden by subclasses to specify how they are partitioned. */
    @transient val partitioner: Option[Partitioner] = None
    5、首选位置 可选 计算数据时,可通过不同节点的状态决定计算节点位置 
    /**
     * Optionally overridden by subclasses to specify placement preferences.
     */
    protected def getPreferredLocations(split: Partition): Seq[String] = Nil

    2、RDD 执行原理 

      从计算的角度来讲,数据处理过程中需要计算资源(内存&CPU)和计算模型(逻辑)。执行时,需要将计算资源和计算模型进行协调和整合。Spark框架在执行时,先申请资源,然后将应用程序的数据处理逻辑分解成一个一个的计算任务。然后将任务发到已经分配资源的计算节点上,按照指定的计算模型进行数据计算。最后得到计算结果。RDD是Spark框架中用于数据处理的核心模型,接下来我们看看,在Yarn环境中,RDD的工作原理

     1、启动 Yarn

     2、Spark 通过申请资源创建调度节点和计算节点

     

     3、spark 框架根据将计算逻辑根据计算需求分区划分成不同的任务;

    4、调度节点将任务根据计算节点状态发送到对应的计算节点进行计算

     

    从以上流程可以看出RDD在整个流程中主要用于将逻辑进行封装,并生成Task发送给Executor节点执行计算,接下来我们就一起看看Spark框架中RDD是具体是如何进行数据处理的。

     3、RDD的创建

     1、读取外部文件创建RDD

    启动 spark-shell 

    cd /opt/module/spark_local
    [hui@hadoop103 spark_local]$ bin/spark-shell 

    读取外部文件创建RDD


    scala> val line=sc.textFile("README.md");
    line: org.apache.spark.rdd.RDD[String] = README.md MapPartitionsRDD[1] at textFile at <console>:24

    scala> line.first();
    res0: String = # Apache Spark

    scala> line.count();
    res1: Long = 108

    这里读取了自带的 一个 README.md 文档, lines.count() 返回了 文档里的行数,lines.first() 返回了第一行

    我们看下 sc 是什么

    scala> sc
    res3: org.apache.spark.SparkContext = org.apache.spark.SparkContext@2dcbf825
    scala> lines
    res4: org.apache.spark.rdd.RDD[String] = README.md MapPartitionsRDD[1] at textFile at <console>:24

    这里的 sc 就是 spark-shell 启动时创建的上下文环境对象。lines 是我们读取文件创建的RDD对象。

     IDEA 中读取外部文件创建RDD

    object Spark01_RDD_file {
      def main(args: Array[String]): Unit = {
        //todo 准备环境
        val spekConf = new SparkConf().setMaster("local[*]").setAppName("RDD") //[*] 表示当前系统最大可用CPU核数
        val sc = new SparkContext(spekConf)
        //todo 创建RDD
        //文件中创建RDD,经文件数据作为spark处理数据的源头
        // path 路径默认以当前环境的根路径为基准,可用写绝对路径,也可以写相对路径
        // //val rdd: RDD[String] = sc.textFile("dates/1.txt")
        // path 可用是具体路径,直接读取路径下的所有文件
        //val rdd = sc.textFile("dates")
        // path 可用是具体路径,+ 通配符
        val rdd = sc.textFile("dates/1*.txt")
        rdd.collect().foreach(println)
        sc.stop()
      }
    }

    2、读取集合数据创建RDD

    scala> val input = sc.parallelize(List(1,2,3,4,4))
    input: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
    
    scala> val mapRDD = input.map(x=>x*2)
    mapRDD: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[1] at map at <console>:26
    
    scala> println(mapRDD.collect().mkString(","))
    2,4,6,8,8  

    这里我们通过一个简单的list 来创建RDD,并调用了 map 方法对集合做了一个操作。

     IDEA 读取集合数据创建RDD

    object Spark01_RDD_Memory {
      def main(args: Array[String]): Unit = {
        //todo 准备环境
        val spekConf = new SparkConf().setMaster("local[*]").setAppName("RDD") //[*] 表示当前系统最大可用CPU核数
        val sc = new SparkContext(spekConf)
        //todo 创建RDD
        //内存中创建RDD,经内存数据作为spark处理数据的源头
        val seq = Seq[Int](1, 2, 3, 4)
        //parallelize 并行
        // val rdd = sc.parallelize(seq)
        // makeRDD 底层调用了 parallelize  方法
        val rd  = sc.makeRDD(seq)
     
       /*
        def makeRDD[T: ClassTag](
        seq: Seq[T],
        numSlices: Int = defaultParallelism): RDD[T] = withScope {
        parallelize(seq, numSlices)  
       */
        rd.foreach(println) 
          /*
       def collect(): Array[T] = withScope {
      val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray)
      Array.concat(results: _*)
    }
       */
        sc.stop()//todo 关闭环境
      }
    }

  • 相关阅读:
    高并发系统设计思考笔记
    面试突击74:properties和yml有什么区别?
    面试突击86:SpringBoot 事务不回滚?怎么解决?
    面试突击82:SpringBoot 中如何操作事务?
    面试突击75:SpringBoot 有几种读取配置文件的方法?
    面试突击81:什么是跨域问题?如何解决?
    面试突击73:IoC 和 DI 有什么区别?
    面试突击85:为什么事务@Transactional会失效?
    一文快速上手 Nacos 注册中心+配置中心!
    面试突击72:输入URL之后会执行什么流程?
  • 原文地址:https://www.cnblogs.com/wdh01/p/16003177.html
Copyright © 2020-2023  润新知