Spark RDD运行原理详解

弹性分布式数据集RDD表示一个分区数据元素的集合,可以在其上进行并行操作。它是Spark的主要数据抽象概念。它是Spark库中定义的一个抽象类。

1.设计背景

许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘工具,共同之处是,不同计算阶段之间会重用中间结果。目前的MapReduce框架都是把中间结果写入到HDFS中,带来了大量的数据复制、磁盘IO和序列化开销。*RDD就是为了满足这种需求而出现的,它提供了一个抽象的数据架构,我们不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换处理,不同RDD之间的转换操作形成依赖关系,可以实现管道化*,避免中间数据存储。

Spark和MapReduce系统解决办法的思路相反,它设计了统一的编程抽象—-弹性分布式数据集(RDD),这种全新的模型可以令用户直接控制数据的共享,使得用户可以指定数据存储到硬盘还是内存、控制数据的分区方法和数据集上进行的操作。RDD不仅增加了高效的数据共享原语,而且大大增加了其通用性。

2.RDD概念

Spark编程模型是弹性分布式数据集(Resilient Distributed Dataset,RDD),它是MapReduce模型的扩展和延伸,但它解决了MapReduce的缺陷:在并行计算阶段高效地进行数据共享

一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的不同节点上进行并行计算。RDD提供了一种高度受限的共享内存模型,即RDD是只读的记录分区的集合,不能直接修改,只能基于稳定的物理存储中的数据集创建RDD,或者通过在其他RDD上执行确定的转换操作(如mapjoingroup by)而创建得到新的RDD

RDD概念的来源论文:The original paper that gave birth to the concept of RDD is Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing by Matei Zaharia, et al.

2.1RDD运行过程

RDD典型的执行过程如下:

  • 1、RDD读入外部数据源进行创建,利于使用textFile函数加载本地数据;
  • 2、RDD经过一系列的转换(Transformation)操作,每一次都会产生不同的RDD,供给狭义转换作使用,这里的Transformation操作就是filter函数;
  • 3、最后一个RDD经过“动作”(Action)操作进行转换,并输出到外部数据源。

《Spark RDD运行原理详解》 image.png

RDD的创建和转换方法都是惰性操作。当Spark应用调用操作方法或者保存RDD至存储系统的时候,RDD的转换计算才真正执行。惰性操作的好处:惰性操作使得Spark可以高效的执行RDD计算。直到Spark应用需要操作结果时才进行计算,Spark可以利用这一点优化RDD操作。这使得操作流水线化,而且还避免在网路间不必要的数据传输。

这一系列处理称为一个Lineage(血缘关系),即DAG拓扑排序的结果优点:

  • 惰性调用、管道化、避免同步等待、不需要保存中间结果、每次操作变得简单

《Spark RDD运行原理详解》 image.png

3.RDD特性

总体而言,Spark采用RDD以后能够实现高效计算的原因主要在于:

  • 1、高效的容错性。
    • 传统方式:现在的分布式共享内存、键值存储、内存数据库等,为了实现容错,必须在集群节点之间进行数据复制或者记录日志,也就是在节点之间会发生大量的数据传输,这对于数据密集型应用而言会带来很大的开销。
    • RDD方式:在RDD的设计中,数据只读,不可修改,如果要修改数据,必须从父RDD转换到子RDD,由此在不同的RDD之间建立了血缘关系。所以,RDD是一种天生具有具有容错机制的特殊集合,不需要通过数据冗余的方式(比如检查点)实现容错,而只需要通过RDD父子依赖(血缘)关系重算计算得到丢失的分区来实现容错,无须回滚整个系统,这样就避免了数据复制的高开销,而且重算过程可以在不同节点并行进行,实现了高效的容错。
    • 此外:RDD提供的转换操作都是一些粗粒度的操作(比如map、filter和join),RDD依赖关系只需要记录这种粗粒度的转换操作,而不需要记录具体的数据和各种细粒度操作的日志,这就大大降低了数据密集型应用中容错开销。
  • 2、中间结果持久化到内存,数据在内存中的多个RDD操作之间进行传递,不需要“落地”到磁盘上,避免了不必要的读写磁盘开销。
  • 3、存放的数据可以是Java对象,避免了不必要的对象序列化和反序列化。

4.RDD之间的依赖关系

RDD是易转换、已操作的,这意味着用户可以从已有的RDD转换出新的RDD转换出新的RDD。新、旧RDD之间必定存在这某种联系,这种联系称为RDD依赖关系。

  • 窄依赖:父RDD的每个子分区最后被其子RDD的一个分区所依赖,也就是说子RDD的每个分区依赖于常数个父分区,子RDD每个分区的生成与父RDD的数据规模无关。
  • 宽依赖:父RDD的每个分区被其子RDD的多个分区所依赖,子RDD每个分区的生成与父RDD的数据规模相关。

《Spark RDD运行原理详解》 image.png

5.Stage的划分

Spark通过分析各个RDD的依赖关系生成了DAG,再通过分析各个RDD中的分区之间的依赖关系来决定如何划分Stage,具体划分方法是:

  • DAG中进行反向解析,遇到宽依赖就断开
  • 遇到窄依赖就把当前的RDD加入到Stage
  • 将窄依赖尽量划分在同一个Stage中,可以实现流水线计算

5.1流水线操作实例

分区7通过map操作生成的分区9,可以不用等待分区8到分区10这个map操作的计算结束,而是继续进行union操作,得到分区13,这样流水线执行大大提高了计算的效率。RDD被分成三个Stage,在Stage2中,从mapunion都是窄依赖,这两步操作可以形成一个流水线操作。

《Spark RDD运行原理详解》 image.png

6.RDD运行过程

通过上述对RDD概念、依赖关系和Stage划分的介绍,结合之前介绍的Spark运行基本流程,再总结一下RDD在Spark架构中的运行过程:

  • 1、创建RDD对象;
  • 2、SparkContext负责计算RDD之间的依赖关系,构建DAG
  • 3、DAGScheduler负责把DAG图分解成多个Stage,每个Stage中包含了多个Task,每个Task会被TaskScheduler分发给各个WorkerNode上的Executor去执行。

《Spark RDD运行原理详解》 image.png

参考资料

http://dblab.xmu.edu.cn/post/bigdataroadmap/

    原文作者:Michaelhbjian
    原文地址: https://www.jianshu.com/p/a5488d83598a
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞