Spark RDD的依赖于DAG的工作原理

在进行本篇之前,如果还有对Spark的一些基础概念不太明白的可以参考一下这篇博文:
Spark核心组件、运行架构

RDD的依赖

RDD是一种弹性分布式数据集,我们以图示的形式来展示一下它的原理:

在这里插入图片描述

RDD的宽窄依赖

Lineage:血统、遗传

  • RDD最重要的特性之一,保存了RDD的依赖关系;
  • RDD实现了基于Lineage的容错机制;
    依赖关系
    宽依赖:一个父RDD的分区被子RDD的多个分区使用;
    在这里插入图片描述
    在这里插入图片描述
    窄依赖:一个父RDD的分区被子RDD的一个分区使用;
    在这里插入图片描述
    例如union:
    在这里插入图片描述
    在这里插入图片描述
    常见的宽依赖有:groupByKey,partitionBy,reduceByKey,Join(父RDD不是hash-partitioned :除此之外的,rdd 的join api是宽依赖)。
    常见的窄依赖有:map,filter,union,mapPartitions,mapValues,join(父RDD是hash-partitioned :如果JoinAPI之前被调用的RDD API是宽依赖(存在shuffle), 而且两个join的RDD的分区数量一致,join结果的rdd分区数量也一样,这个时候join api是窄依赖)。
    宽依赖对比窄依赖
  • 宽依赖对应shuffle操作,需要在运行时将同一个父RDD的分区传入到不同的子RDD分区中,不同的分区可能位于不同的节点,就可能涉及多个节点间数据传输
  • 当RDD分区丢失时,Spark会对数据进行重新计算,对于窄依赖只需重新计算一次子RDD的父RDD分区。相比于宽依赖,窄依赖对优化更有利。

DAG工作原理

根据RDD之间的依赖关系,形成一个DAG(有向无环图)。
DAGScheduler将DAG划分为多个Stage

  • 划分依据:是否发生宽依赖(Shuffle)
  • 划分规则:从后往前,遇到宽依赖切割为新的Stage
  • 每个Stage由一组并行的Task组成
    DAGScheduler
    有向无环图调度器。
  • 基于DAG划分Stage 并以TaskSet的形势提交Stage给TaskScheduler;
  • 负责将作业拆分成不同阶段的具有依赖关系的多批任务;
  • 最重要的任务之一就是:计算作业和任务的依赖关系,制定调度逻辑。
  • 在SparkContext初始化的过程中被实例化,一个SparkContext对应创建一个DAGScheduler。
    在这里插入图片描述
    TaskSceduler:
    任务调度器。将TaskSet提交给Worker(集群)运行并返回结果;负责每个具体任务的实际物理调度。
    在这里插入图片描述
    下面来张总表供大家仔细查看:
    在这里插入图片描述
    在这里插入图片描述

划分Stage的原因

数据本地化

  • 移动计算,而不是移动数据;
    -保证一个Stage内不会发生数据移动;

建议

  • 尽量避免Shuffle
  • 提前部分聚合减少数据移动

Spark Shuffler过程

在分区之间重新分配数据

  • 父RDD中同一分区中的数据按照算子要求重新进入子RDD的不同分区中
  • 中间结果写入磁盘
  • 由子RDD拉取数据,而不是由父RDD推送
  • 默认情况下,Shuffle不会改变分区数量
    在这里插入图片描述