Spark中,RDD概述(五大属性,弹性介绍,5个特性)

您所在的位置:网站首页 接口的概念和特点有哪些 Spark中,RDD概述(五大属性,弹性介绍,5个特性)

Spark中,RDD概述(五大属性,弹性介绍,5个特性)

2024-05-29 14:51| 来源: 网络整理| 查看: 265

1 什么是RDD

RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark 中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。在Spark 中,对数据的所有操作不外乎创建RDD、转化已有RDD 以及调用RDD 操作进行求值。每个RDD 都被分为多个分区,这些分区运行在集群中的不同节点上。RDD 可以包含Python、Java、Scala 中任意类型的对象, 甚至可以包含用户自定义的对象。RDD 具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD 允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。RDD 支持两种操作:transformation操作和action操作。RDD 的转化操作是返回一个新的RDD 的操作,比如map()和filter(),而action操作则是向驱动器程序返回结果或把结果写入外部系统的操作。比如count() 和first()。 Spark 采用惰性计算模式,RDD 只有第一次在一个行动操作中用到时,才会真正计算。Spark 可以优化整个计算过程。默认情况下,Spark 的RDD 会在你每次对它们进行行动操作时重新计算。如果想在多个行动操作中重用同一个RDD , 可以使用RDD.persist() 让Spark 把这个RDD 缓存下来。

2 RDD 的属性

从RDD的abstract class中可知:

* Internally, each RDD is characterized by five main properties: * * - A list of partitions * - A function for computing each split * - A list of dependencies on other RDDs * - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned) * - Optionally, a list of preferred locations to compute each split on (e.g. block locations for * an HDFS file)

1) 一组分片(Partition),即数据集的基本组成单位。 对于RDD 来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD 时指定RDD 的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。protected def getPartitions: Array[Partition]2) 一个计算每个分区的函数。 Spark 中RDD 的计算是以分片为单位的,每个RDD都会实现compute 函数以达到这个目的。ompute 函数会对迭代器进行复合,不需要保存每次计算的结果。def compute(split: Partition, context: TaskContext): Iterator[T]3) RDD 之间的依赖关系。 RDD 的每次转换都会生成一个新的RDD,所以RDD 之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark 可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD 的所有分区进行重新计算。protected def getDependencies: Seq[Dependency[_]] = deps ​​​​​​​4) 一个Partitioner, 即RDD 的分片函数(分区器)。 当前Spark 中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value 的RDD , 才会有Partitioner, 非key-value 的RDD 的Parititioner 的值是None。Partitioner 函数不但决定了RDD 本身的分片数量, 也决定了parent RDD Shuffle 输出时的分片数量。@transient val partitioner: Option[Partitioner] = None5) 一个列表, 存储存取每个Partition 的优先位置( preferred location)。 对于一个HDFS 文件来说,这个列表保存的就是每个Partition 所在的块的位置。按照“移动数据不如移动计算”的理念,Spark 在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。protected def getPreferredLocations(split: Partition): Seq[String] = Nil RDD 是一个应用层面的逻辑概念。一个RDD 多个分片。RDD 就是一个元数据记录集,记录了RDD 内存所有的关系数据。

3 RDD 弹性

1) 自动进行内存和磁盘数据存储的切换 Spark 优先把数据放到内存中,如果内存放不下,就会放到磁盘里面,程序进行自动的存储切换2) 基于血统的高效容错机制 在RDD 进行转换和动作的时候,会形成RDD 的Lineage 依赖链,当某一个RDD 失效的时候,可以通过重新计算上游的RDD 来重新生成丢失的RDD 数据。3) Task 如果失败会自动进行特定次数的重试 RDD 的计算任务如果运行失败,会自动进行任务的重新计算,默认次数是4 次。4) Stage 如果失败会自动进行特定次数的重试 如果Job 的某个Stage 阶段计算失败,框架也会自动进行任务的重新计算,默认次数也是4 次。5) Checkpoint 和Persist 可主动或被动触发 RDD 可以通过Persist 持久化将RDD 缓存到内存或者磁盘,当再次用到该RDD 时直接读取就行。也可以将RDD 进行检查点,检查点会将数据存储在HDFS 中,该RDD 的所有父RDD 依赖都会被移除。6) 数据调度弹性 Spark 把这个JOB 执行模型抽象为通用的有向无环图DAG,可以将多Stage 的任务串联或并行执行,调度引擎自动处理Stage 的失败以及Task 的失败。7) 数据分片的高度弹性 可以根据业务的特征,动态调整数据分片的个数,提升整体的应用执行效率。RDD 全称叫做弹性分布式数据集(Resilient Distributed Datasets),它是一种分布式的内存抽象,表示一个只读的记录分区的集合,它只能通过其他RDD 转换而创建,为此,RDD支持丰富的转换操作(如map, join, filter, groupBy 等),通过这种转换操作,新的RDD 则包含了如何从其他RDDs 衍生所必需的信息,所以说RDDs 之间是有依赖关系的。基于RDDs 之间的依赖,RDDs 会形成一个有向无环图DAG,该DAG 描述了整个流式计算的流程,实际执行的时候,RDD 是通过血缘关系(Lineage)一气呵成的,即使出现数据分区丢失,也可以通过血缘关系重建分区,总结起来,基于RDD 的流式计算任务可描述为:从稳定的物理存储(如分布式文件系统)中加载记录,记录被传入由一组确定性操作构成的DAG,然后写回稳定存储。另外RDD 还可以将数据集缓存到内存中,使得在多个操作之间可以重用数据集,基于这个特点可以很方便地构建迭代型应用(图计算、机器学习等)或者交互式数据分析应用。可以说Spark 最初也就是实现RDD 的一个分布式系统,后面通过不断发展壮大成为现在较为完善的大数据生态系统,简单来讲,Spark-RDD 的关系类似于Hadoop-MapReduce 关系。

4 RDD 特点

RDD 表示只读的分区的数据集,对RDD 进行改动,只能通过RDD 的转换操作,由一个RDD 得到一个新的RDD,新的RDD 包含了从其他RDD 衍生所必需的信息。RDDs 之间存在依赖,RDD 的执行是按照血缘关系延时计算的。如果血缘关系较长,可以通过持久化RDD 来切断血缘关系。4.1 分区 RDD 逻辑上是分区的,每个分区的数据是抽象存在的,计算的时候会通过一个compute函数得到每个分区的数据。如果RDD 是通过已有的文件系统构建,则compute 函数是读取指定文件系统中的数据,如果RDD 是通过其他RDD 转换而来,则compute 函数是执行转换逻辑将其他RDD 的数据进行转换。4.2 只读 RDD 是只读的,要想改变RDD 中的数据,只能在现有的RDD 基础上创建新的RDD。 由一个RDD 转换到另一个RDD, 可以通过丰富的操作算子实现, 不再像MapReduce那样只能写map 和reduce 了,如下图所示。

RDD 的操作算子包括两类,一类叫做transformations,它是用来将RDD 进行转化,构建RDD 的血缘关系;另一类叫做actions,它是用来触发RDD 的计算,得到RDD 的相关计算结果或者将RDD 保存的文件系统中。下图是RDD 所支持的操作算子列表。

4.3 依赖 RDDs 通过操作算子进行转换,转换得到的新RDD 包含了从其他RDDs 衍生所必需的信息,RDDs 之间维护着这种血缘关系,也称之为依赖。如下图所示,依赖包括两种,一种是窄依赖, RDDs 之间分区是一一对应的, 另一种是宽依赖, 下游RDD 的每个分区与上游RDD(也称之为父RDD)的每个分区都有关,是多对多的关系。 通过RDDs 之间的这种依赖关系,一个任务流可以描述为DAG(有向无环图),如下图所示,在实际执行过程中宽依赖对应于Shuffle(图中的reduceByKey 和join),窄依赖中的所有转换操作可以通过类似于管道的方式一气呵成执行(图中map 和union 可以一起执行)。

4.4 缓存 如果在应用程序中多次使用同一个RDD,可以将该RDD 缓存起来,该RDD 只有在第一次计算的时候会根据血缘关系得到分区的数据,在后续其他地方用到该RDD 的时候,会直接从缓存处取而不用再根据血缘关系计算,这样就加速后期的重用。如下图所示,RDD-1经过一系列的转换后得到RDD-n 并保存到hdfs,RDD-1 在这一过程中会有个中间结果,如果将其缓存到内存,那么在随后的RDD-1 转换到RDD-m 这一过程中,就不会计算其之前的RDD-0 了。

4.5 checkpoint 虽然RDD 的血缘关系天然地可以实现容错,当RDD 的某个分区数据失败或丢失,可以通过血缘关系重建。但是对于长时间迭代型应用来说,随着迭代的进行,RDDs 之间的血缘关系会越来越长,一旦在后续迭代过程中出错,则需要通过非常长的血缘关系去重建,势必影响性能。为此,RDD 支持checkpoint 将数据保存到持久化的存储中,这样就可以切断之前的血缘关系, 因为checkpoint 后的RDD 不需要知道它的父RDDs 了, 它可以从checkpoint处拿到数据。 给定一个RDD 我们至少可以知道如下几点信息:1、分区数以及分区方式;2、由父RDDs衍生而来的相关依赖信息;3、计算每个分区的数据,计算步骤为:1)如果被缓存,则从缓存中取的分区的数据;2)如果被checkpoint,则从checkpoint 处恢复数;3)根据血缘关系计算分区的数据。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3