Spark RDD的stage划分和容错

一、要想更深一度的了解Spark RDD,首先我们得初步了解一下Spark RDD,那么问题就来了,什么是RDD呢?

RDD( resilient distributed dataset ) 弹性分布式数据集;RDD代表是一个不可变的、可分区的、支持并行计算的元素集合(类似于Scala中的不可变集合),RDD可以通过HDFS、Scala集合、RDD转换、外部的数据集(支持InputFormat)获得;并且我们可以通知Spark将RDD持久化在内存中,可以非常高效的重复利用或者在某些计算节点故障时自动数据恢复;

二、了解完RDD之后,我们来分析一下它的原理

RDD依赖——lineage(血统 | 血缘)

在对数据源RDD应用转换操作时,产生的新的RDD会有一种依赖关系称为血统(Lineage); Spark应用在计算时会根据血统(lineage)逆向推导出所有Stage(阶段),每一个Stage的分区数量决定了任务的并行度,一个Stage实现任务的本地计算(大数据计算时网络传输时比较耗时的)

object WordCountApplication {
  def main(args: Array[String]): Unit = {

    // spark word count应用
    val conf = new SparkConf().setMaster("local[*]").setAppName("wordcount")
    val sc = new SparkContext(conf)

    // rdd由两个分区构成
    val rdd = sc.makeRDD(List("Hello Kafka", "Hello Scala", "Hello Hadoop"), 2)  // rdd1

    rdd
      .flatMap(_.split("\\s"))   //  rdd1 --> rdd2
      .map((_, 1L))              //  rdd2 --> rdd3
      .groupByKey(3)             //  rdd3 --> rdd4
      .map(t2 => (t2._1, t2._2.size))  // rdd4 --> rdd5
      .sortBy(_._2, false, 2)    //...
      .foreach(t2 => println(t2._1 + "\t" + t2._2))

    sc.stop()
  }
}

宽窄依赖

RDD之间血缘关系可以详细分为两种:宽依赖(Wide Dependency)和窄依赖(Narrow Dependency);

  • 窄依赖(Narrow Dependency): 父RDD的一个分区对应一个子RDD的分区(1:1)或者多个父RDD的分区对应一个子RDD的分区(N:1);
  • 宽依赖(Wide Dependency): 父RDD的一个分区对应多个子RDD的分区(1:N);
  • 注意:宽、窄依赖和Spark应用的Stage划分有极为紧密关系;
    在这里插入图片描述
    我们发现:Spark在拆分阶段时,发现宽依赖立即划分Stage,如果发现窄依赖归属于同一个Stage

在这里插入图片描述

RDD的容错

Spark计算时当某些Task在计算时未正确处理,则会触发RDD的容错机制;容错机制分为三种情况:

  • 重新计算(默认):如果只有窄依赖只需要重新计算故障Task数据分区即可;如果既有宽依赖又有窄依赖,则需要重新计算故障任务前的所有分区的数据;
  • RDD持久化:将某一个RDD持久化内存或者磁盘中;当Task故障时,直接从持久化RDD中恢复数据即可;
  • Checkpoint(检查点): 可以对某一个RDD设定检查点,RDD的数据信息则会持久化到一个共享的分布式文件系统中(HDFS),当检查点设定结束后,整个血统的链路会中断,检查点机制比较适合血统链路较长Spark应用,建议设置给宽依赖RDD;
RDD持久化(persist)
// 持久化方法 MEMORY_ONLY
rdd.persist()

// 缓存方法 MEMORY_ONLY
rdd.cache() 

// 设定持久化级别
rdd.persist(StorageLevel.MEMORY_AND_DISK)

// 取消RDD持久化方法
rdd.unpersist()

在这里插入图片描述
注意:

  • 对RDD进行持久化时可以选择内存、磁盘、内存+磁盘这样的存储介质,如果Spark集群的内存空间足够大,推荐使用MEMORY_ONLY
  • MEMORY_ONLY_2中的_2表示除过增加数据副本
  • MEMORY_ONLY_SER中的_SER表示将RDD中的数据序列化后存储
检查点机制(checkpoint)
// 设定检查点数据的存放目录
sc.setCheckpointDir("hdfs://SparkOnStandalone:9000/checkpoint")

// rdd由两个分区构成
val rdd = sc.makeRDD(List("Hello Kafka", "Hello Scala", "Hello Hadoop"), 2)

val groupRdd = rdd
.flatMap(_.split("\\s"))
.map((_, 1L))
.groupByKey(3)

// 标记检查点
groupRdd.checkpoint()

groupRdd.map(t2 => (t2._1, t2._2.size))
.sortBy(_._2, false, 2)
.foreach(t2 => println(t2._1 + "\t" + t2._2))

sc.stop()

在这里插入图片描述

发布了24 篇原创文章 · 获赞 1 · 访问量 501

猜你喜欢

转载自blog.csdn.net/Mr_YXX/article/details/105002680