Spark之RDD解析

一、RDD定义

分布式弹性数据集,只读的分区集合,不同分区可以被保存在不同的节点上,从而进行并行计算

二、RDD操作

RDD通常通过Hadoop上的文件,即HDFS文件或者Hive表,来进行创建;有时也可以通过应用程序中的集合来创建.

  • 转换

    指定RDD之间的相互依赖关系 粗粒度的数据转换操作 适合对数据集执行相同操作的批处理式应用,而不适合用于需要异步、细粒度状态的应用

    比如map、filter、groupBy、join等,接受RDD并返回RDD

  • 行动

    执行计算并输出指定形式,接受RDD返回并不一定是RDD,可能是一个值,也可能是结果,比如count,collect操作

惰性调用

RDD只有在行动操作发生时才会进行真正计算,前面的转换操作只是记录下一些基础数据集合和RDD生成的轨迹。

Spark之RDD解析

通过输入的数据集,创建RDD,经过一系列转换,最后在F处进行Action操作,形成DAG拓扑排序,这一过程称为血缘关系(Lineage)。

采用惰性调用,实现RDD转换的管道化,避免转换操作中的数据等待。

三、RDD特性

  • 基于内存进行迭代计算。不同计算阶段之间会重用中间结果,即一个阶段的输出结果会作为下一个阶段的输入

  • 高效的容错性。RDD不需要冗余和备份,一旦某一分区数据丢失,只需要通过血缘关系重新计算即可得到丢失的数据,不需要回滚整个系统,充分避免了数据复制的巨大开销,由于自身计算是不同节点之间并行的特性,实现高效容错

  • 节约数据交换开销。中间结果持久化到内存,数据在多个RDD之间传递,不需要存入磁盘,避免读写产生的IO开销。存的数据可以是JavaBean,避免序列化和反序列化开销

  • 弹性。RDD的数据默认情况下存放在内存中的,但是在内存资源不足时,Spark会自动将RDD数据写入磁盘

四、RDD依赖关系

  • 宽依赖

    一个父RDD的一个分区对应一个子RDD的多个分区

  • 窄依赖

    父RDD的一个分区只被一个子RDD的一个分区所使用

Spark之RDD解析

主要通过看父RDD对应的子RDD是否为单个,是窄依赖,否则宽依赖。
窄依赖的数据恢复较快,只需要根据父RDD计算分区即可,
而宽依赖可能涉及多个父RDD

Shuffle操作

分区之间执行行动操作,产生数据交互,比如将集群多个节点的key拉到同一个节点进行聚合操作

五、阶段划分

spark通过生成的依赖关系进行阶段划分:在DAG中进行反向解析,遇到宽依赖就断开,将窄依赖尽量划分到同一阶段,实现流水线计算

Spark之RDD解析
上图中,划分成三个阶段,A到B是宽依赖,B,F到G也是宽依赖,以宽依赖为节点,划分成三个阶段。每个阶段内都没有Shuffle操作,阶段内是任务集合,结合会被提交给任务调度器,任务调度器将任务分发到不同Executor上进行计算.

RDD运行也就是以下过程:

  1. 根据数据集创建RDD
  2. 建立RDD之间的依赖关系,构建DAG
  3. 对DAG划分阶段,将阶段任务分发到具体工作节点进行执行。
  4. 汇总执行结果输出