Spark入门篇——RDD的血缘

2023-10-10 18:10
文章标签 spark rdd 入门篇 血缘

本文主要是介绍Spark入门篇——RDD的血缘,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

RDD的血缘

概述

划分依赖的背景

划分以来的依据

窄依赖

宽依赖

 join的依赖

宽依赖

 窄依赖

 依赖与Stage的划分

Stage的类别

 依赖与容错

转换算子中间发生失败

DAG的生成

总结


RDD的血缘

概述

RDD可以从本地集合并行化、从外部文件系统、其他RDD转化得到,能从其他RDD通过Transformation创建新的RDD的原因是RDD之间有依赖关系(Dependency代表了RDD之间的依赖关系,即血缘(Lineage)),RDD和他依赖的父RDD有两种不同的类型,即宽依赖(wide dependency)和窄依赖(narrow dependency)。

划分依赖的背景

  1. 从计算过程,窄依赖是数据以管道的方式经一系列计算操作可以运行在一个集群节点上,,例如:map、filter。宽依赖则可能需要将数据跨节点传输后运行(如groupByKey),有点类似于MR的shuffle过程。
  2. 从失败恢复来看,窄依赖恢复起来更高效,因为他只需要找到父RDD的一个对应分区即可,而且可以在不同节点上并行计算做恢复。宽依赖则牵扯到父RDD的多个分区,恢复起来相对复杂一些。
  3. 在这里我们引入一个新的概念,Stage。Stage可以简单的理解为是由一组RDD组成的可进行优化的执行计划。若RDD的衍生关系为窄依赖,则可以放在同一个stage中运行。若RDD的依赖关系为宽依赖,则要划分到不同的Stage中。这样Spark在执行任务时,会按照Stage的划分,生成一个完整的最优的执行计划。

划分以来的依据

划分宽依赖和窄依赖的关键点在:分区的依赖关系

也就是说父RDD的一个分区的数据,是给子RDD的一个分区,还是给子RDD的所有分区。

父RDD的每一个分区,是被一个子RDD的一个分区依赖(一对一),就是窄依赖。

如果父RDD的每一个分区,是被子RDD的各个分区所依赖(一对多),就是宽依赖。

一旦有宽依赖发生,就意味着会发生数据的shuffle。发生了shuffle也就意味着生成了新的stage。

窄依赖

窄依赖是指父RDD的一个分区,被子RDD的一个分区所依赖(一对一)

输入输出一对一的算子,且结果RDD的分区结构不变,主要是map/flatMap/filter

输入输出一对一的算子但结果RDD的分区结构发生了变化,如union/coalesce

宽依赖

宽依赖指的是父RDD的一个分区,被子RDD的所有个分区依赖(一对多)。 

对单个RDD基于key进行重组和归并,如groupByKey,reduceByKey等。

对于两个RDD基于key进行join和重组。如join(父RDD不是hash-Partitioned)

需要进行分区,如partitionBy

 join的依赖

宽依赖

 窄依赖

 依赖与Stage的划分

Spark将窄依赖划分到同一个Stage中,因为他们可以进行流水线计算。而宽依赖往往意味着shuffle操作,这也是Spark划分stage的主要边界。一个Stage的开始就是从外部存储或者shuffle结果中读取数据;一个Stage的结束就是发生shuffle或者生成结果时。只要发生了shuffle,就会有Stage的划分。

Stage的类别

一个Job是由action算子触发的,一个Job中包含一个或者多个Stage,其中分为ResultStage(一个)和ShuffleStage(多个)。

 依赖与容错

宽、窄依赖的概念不知用于在stage的划分,对容错特很有用,RDD的Lineage会记录RDD的元数据信息和转换行为,当该RDD的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。

dependency代表了RDD之间的依赖关系,即血缘(Lineage)。

数据进行切片后,每个分区对应的数据,是固定的。(其实偏移量和结束的偏移量)

分区是在driver端生成的,即使某一个分区挂掉了也没关系,driver端会根据rdd的依赖关系,重启新的task进行任务执行。

转换算子中间发生失败

  1. 运算是窄依赖:只要把丢失的父RDD分区重新计算即可,跟其他节点没有依赖,这样可以大大减少恢复丢失的数据分区的开销。
  2. 运算是宽依赖:需要父RDD的所有分区都存在,重算代价较高。
  3. 如果整个节点挂掉,driver会把任务在其他的节点中的executor中重启。
  4. 缓存或者增加检查点:当Lineage特别长或者有宽依赖的时候,主动调用checkpoint把当前数据写入稳定存储,作为检查点。但checkpoint会产生磁盘开销。因为做checkpoint时需要重新计算该RDD的内容,所以该RDD最好已经在内存中缓存了

为了提高运算的效率,更好的解决容错问题,spark提供了一系列的解决方案,缓存,检查点(checkpoint)

缓存:把rdd的数据,写入到内存或者磁盘

checkpoint: 写入到hdfs中

使用缓存和持久化来提升运行效率

DAG的生成

DAG叫做有向无环图,指任意一条边有方向,且不存在环路的图。其中点代表RDD,边代表RDD之间的依赖关系。

在Spark中每一个操作生成一个RDD,RDD之间连一条边,最后这些RDD和它们之间的边组成一个有向无环图,这个就是Spark的DAG图。原始RDD通过一系列的转换就形成了DAG,根据RDD之间的依赖关系的不同将DAG划分为不同的Stage,对于窄依赖,分区的转换处理在Stage中完成计算。对于宽依赖,由于shuffle的存在,只能在parentRDD处理完成之后,才能开始接下来的计算,因此宽依赖是划分Stage的依据

总结

DAG是有向无环图,代表着RDD的转换过程,其实就是代表着数据的流向。

DAG是有边界的,有开始,有结束。通过sparkContext创建RDD就是开始,触发action就会生成一个完整的DAG。DAG会被切分为多个Stage(阶段),切分的依据就是宽依赖(Shuffle),会先提交前面的stage,然后提交后面的stage,一个stage中根据最后一个RDD的分区出划分出多个Task,多个Task可以并行执行。

 

这篇关于Spark入门篇——RDD的血缘的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/182164

相关文章

墨刀原型工具-小白入门篇

墨刀原型工具-小白入门篇 简介 随着互联网的发展和用户体验的重要性越来越受到重视,原型设计逐渐成为了产品设计中的重要环节。墨刀作为一款原型设计工具,以其简洁、易用的特点,受到了很多设计师的喜爱。本文将介绍墨刀原型工具的基本使用方法,以帮助小白快速上手。 第一章:认识墨刀原型工具 1.1 什么是墨刀原型工具 墨刀是一款基于Web的原型设计工具,可以帮助设计师快速创建交互原型,并且可以与团队

openfire+spark 在linux下安装,配置

文章转自:点击打开链接 相关软件下载 链接: https://pan.baidu.com/s/1boJs61h 密码: 2wd7 Openfire 在linux下安装和配置 + spark 在windows下配置 本机环境 系统:CentOS 6.7 64 位JDK 1.7 64 位MySQL 5.6 Openfir

任务5.1 初识Spark Streaming

实战概述:使用Spark Streaming进行词频统计 1. 项目背景与目标 背景: Spark Streaming是Apache Spark的流处理框架,用于构建可伸缩、高吞吐量的实时数据处理应用。目标: 实现一个实时词频统计系统,能够处理流式数据并统计文本中的单词出现频率。 2. 技术要点 Spark Streaming集成: 与Spark生态的其他组件如Spark SQL、ML

深度学习入门篇(一)

首先明确什么是机器学习,换言之机器学习程序相较于其他计算机硬编码程序有哪些能力? 硬编码计算机程序试图以极其复杂的形势化规则描述这个世界,但是对于人类而言非常简单的语音和图像却好像不是那么容易以一种形式化的语言来描述的。在追逐计算机智能发展的进程中,人们为此做了大量的努力,比如“知识库方法(Cyc)”和大量的专家系统。最后都难以在业界取得成功,因为尽善尽美形式化描述本身就是难以实现的。 所以A

使用Rcpp提高性能之入门篇

C++能解决的瓶颈问题有: 由于迭代依赖于之前结果,循环难以简便的向量化运算递归函数,或者是需要对同一个函数运算成千上万次R语言缺少一些高级数据结构和算法 我们只需要在代码中写一部分C++代码来就可以处理上面这些问题。后续操作在Windows下进行,你需要安装Rtools,用install.packages("Rcpp")安装新版的Rcpp,最重要一点,你需要保证你R语言时不能是C:/Progr

Spark算子:RDD行动Action操作(3)–aggregate、fold、lookup

aggregate def aggregate[U](zeroValue: U)(seqOp: (U, T) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): U aggregate用户聚合RDD中的元素,先使用seqOp将RDD中每个分区中的T类型元素聚合成U类型,再使用combOp将之前每个分区聚合后的U类型聚合成U类型,特别注意se

Spark算子:RDDAction操作–first/count/reduce/collect/collectAsMap

first def first(): T first返回RDD中的第一个元素,不排序。 scala> var rdd1 = sc.makeRDD(Array(("A","1"),("B","2"),("C","3")),2)rdd1: org.apache.spark.rdd.RDD[(String, String)] = ParallelCollectionRDD[33] at mak

Spark算子:RDD键值转换操作(4)–cogroup/join

cogroup 函数原型:最多可以组合4个RDD,可以通过partitioner和numsPartitions设置 def cogroup[W1, W2, W3](other1: RDD[(K, W1)], other2: RDD[(K, W2)], other3: RDD[(K, W3)], partitioner: Partitioner) :RDD[(K, (Iterable[V],

Spark算子:RDD键值转换操作(3)–groupByKey、reduceByKey、reduceByKeyLocally

groupByKey def groupByKey(): RDD[(K, Iterable[V])] def groupByKey(numPartitions: Int): RDD[(K, Iterable[V])] def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])] 该函数用于将RDD[K,V]中每个K对应

Spark算子:RDD键值转换操作(1)–partitionBy、mapValues、flatMapValues

partitionBy       def partitionBy(partitioner: Partitioner): RDD[(K, V)]       该函数根据partitioner函数生成新的ShuffleRDD,将原RDD重新分区。 scala> var rdd1 = sc.makeRDD(Array((1,"A"),(2,"B"),(3,"C"),(4,"D")),2)rd