Spark三大数据结构之RDD基本介绍

spark核心组件之间的关联

在 Spark 中,一个 Spark 应用程序通常包含一个 Driver 进程和多个 Executor 进程。Driver 进程运行在集群的某个节点上(通常是 Master 节点),它负责整个应用程序的控制和调度。每个 Worker Node 上运行着一个或多个 Executor 进程,每个 Executor 负责在该节点上执行具体的任务。Driver 与 Executor 是一对多的关系,一个 Driver 可以管理多个 Executor。Executor 与 Worker Node 是一对一的关系,每个 Executor 只在一个 Worker Node上运行。

总结

  1. 一个 Spark 应用程序包含一个 Driver 和多个 Executor。
  2. Driver 控制和调度整个应用程序,而 Executor 负责具体任务的执行。
  3. 一个 Driver 可以管理多个 Executor,每个 Executor 运行在一个 Worker Node 上。

Spark三大核心数据结构

  1. RDD(Resilient Distributed Dataset)

    • 描述:RDD 是 Spark 引擎的基本数据结构,用于表示分布式的、可容错的数据集。RDD 具有不可变性、分布式、容错性、惰性计算等特性。

    • 特点:RDD 是一个分区的、只读的、不可修改的数据集,支持并行处理。它提供了一系列的转换操作(如 mapfilterreduce 等)和行动操作(如 collectcountsaveAsTextFile 等),以支持数据的处理和分析。

  2. 累加器(Accumulator)

    • 描述:累加器是一种 Spark 支持的分布式变量,用于在并行计算中进行累加操作。

    • 特点:累加器只能通过关联和交换的方式进行操作,以确保在并行计算中的正确性。它通常用于在分布式计算过程中,每个节点上的任务都能够对其进行局部累加,最后由驱动程序进行全局汇总。

  3. 广播变量(Broadcast Variable)

    • 描述:广播变量是一种用于在 Spark 集群中高效分发大型只读变量的机制。

    • 特点:广播变量通过将变量缓存在每个工作节点上,避免了在每个任务中传递大型变量的开销。这在某些场景下可以显著提高性能。

这三个概念在 Spark 中的使用场景不同:

  • RDD 是用于表示分布式数据集的基本抽象,用于进行分布式计算。

  • 累加器用于在分布式计算中进行全局累加,通常用于计数等操作。

  • 广播变量用于在集群中高效地分发只读变量,以提高任务的性能。

RDD的介绍

rdd和Java中的IO流有些相似,Java中的IO流通过装饰者模式,将字节打印之间加一个字节缓冲区得到几个字节的字符再打印,再在外面增加字符缓冲区然后通过增加一个字符缓冲区,得到一行字符再打印,而RDD则是如同IO流一样优内到外层层包裹,一个RDD如果想要实现一个新的功能则需要创建一个新的RDD将其包裹在里面。

特点:

(1)弹性

【1】存储弹性:内存磁盘自动切换

【2】容错弹性:数据丢失可自动恢复

【3】计算弹性:计算出错重试机制

【4】分片弹性:根据需要重新分片

(2)分布式

数据存储在大数据集群不同节点上

(3)数据集

RDD封装了计算逻辑,并不保存数据

(4)数据抽象

RDD是一个抽象类,需要看具体封装实现

(5)不可变

RDD封装了计算逻辑,不可改变,若要改变只能产生新的RDD,在新的RDD里封装计算逻辑

(6)可分区、并行计算

 

核心属性

(1)分区列表

用于执行并行计算,是实现分布式计算的重要属性

(2)分区计算函数

(3)RDD依赖关系(一份依赖列表)

(4)分区器(将数据进行分区处理)

(5)计算分区的首选位置(判断计算发生到哪个节点效率最优)

 

RDD的创建

(1)从内存中

(2)从文件中

(3)从集合

 

import org.apache.spark.{SparkConf, SparkContext}

object Main {
  def main(args: Array[String]): Unit = {
    val sparkConf=new SparkConf().setMaster("local[*]").setAppName("RDDAPP")
    val sc=new SparkContext(sparkConf)
    // val txtFile=sc.wholeTextFiles("src/main/resources/data") // 以文件为单位读取
    val txtFile=sc.textFile("src/main/resources/data") //以行为单位读取
    val lis=List[Int](1,2,3,4)
    // val rdd=sc.parallelize(seq) // 创建RDD的另一种方法
    val rdd=sc.makeRDD(lis)
    rdd.map(_*2).collect().foreach(println(_))
    txtFile.collect().foreach(println(_))
    sc.stop()

  }

}

 

 

 

RDD集合数据源设置分区并划分数据

i 代表分区数遍历,从0开始(例子:0,1,2)

start = (i * 数量长度)/分区数量

end = ((i+1)*数量长度)/分区数量

(start , end)包头不包尾,代表的是用于划分数据的序号,第一个是0,以此类推。假设(0,2)则包含序号0,1。意味着第一个和第二个数据被划分在该分区。

 

RDD文件来源设置分区数量

默认情况下:

math.min(defaultParallelism,2)

defaultParallelism代表用户设置的工作线程数

用户设置的情况:

用户设置的分区数量实际上是最小数量,具体分区公式如下:

所有文件的总字节数/(分区数量,如果分区为0就改成1)

 

RDD文件来源进行数据分配

(1)数据以行为单位进行分区,与字节数无关

(2)数据读取时以偏移量为单位,且偏移量不会被重新读取

(3)数据分区的偏移量范围计算,包头包尾,任何行在被读取后该行所有内容将会被一次性全部读取,哪怕不在偏移量范围内。注意读取的内容包括占两个字节的回车

(4)如果数据源为多个文件,那么计算分区时以文件为单位进行分区

 
posted @ 2024-01-27 23:10  突破铁皮  阅读(162)  评论(0)    收藏  举报