什么是RDD
RDD:弹性分布式数据集 (Resilient Distributed DataSet),Spark 中最基本的数据抽象。
简单来说RDD 是一种抽象,是 Spark 对于分布式数据集的抽象,它用于囊括所有内存中和磁盘中的分布式数据实体。
我们可以将RDD简单的理解数组,通过数组的方式来理解RDD,下图是RDD和数组的对比
从上表中看出,
首先从概念来说,数组是实体,是一种存储同类元素的数据结构,而RDD是一种抽象,它所囊括的是分布式计算环境中的分布式数据集。也就是每个分片上的数据。
数据跨度即活动范围,数组的“活动范围”很窄,仅限于单个计算节点的某个进程内,而 RDD 代表的数据集是跨进程、跨节点的,它的“活动范围”是整个集群。
至于数组和 RDD 的第三个不同,则是在数据定位方面。在数组中,承载数据的基本单元是元素,而 RDD 中承载数据的基本单元是数据分片。在分布式计算环境中,一份完整的数据集,会按照某种规则切割成多份数据分片。这些数据分片被均匀地分发给集群内不同的计算节点和执行进程,从而实现分布式并行计算。
为了更好的理解RDD,我们需要掌握RDD的4大属性:
- partitions:数据分片
- partitioner:分片切割规则
- dependencies:RDD 依赖
- compute:转换函数
我们以土豆加工和wordcount进行理解:
1.partitions:数据分片,其实就是当前分区的属性,例如每个流水线上干净土豆一同构成"干净土豆"RDD 的 partitions 属性。wordRDD所在的分区集合为wordRDD的partitions属性。
2.partitioner:分片切割规则,这个属性定义了把原始数据集切割成数据分片的切割规则。其实就是土豆怎么分,数据怎么切。例如带泥土豆是从麻袋里随机区分的,而后面的形态沿用前一个RDD的partitioner 属性。正如wordRDD沿用lineRDD的partioner。
3.dependencies:RDD 依赖,每个 RDD 都会通过 dependencies 属性来记录它所依赖的前一个、或是多个 RDD,简称“父 RDD”。如图所示,每个加工形态都是在上一个形态基础上完成。例如wordRDD ,它的父 RDD 是 lineRDD,因此,它的 dependencies 属性记录的是 lineRDD。
4.compute:转换函数,例如,土豆片是由干净土豆经过用刀切完成的,那么土豆片的compute属性为用刀切片。lineRDD经过flatMap生成wordRDD,那么wordRDD的compute属性为flatMap。
RDD 是 Spark 对于分布式数据集的抽象,每一个 RDD 都代表着一种分布式数据形态。 比如 lineRDD,它表示数据在集群中以行(Line)的形式存在;而 wordRDD 则意味着数据的形态是单词,分布在计算集群中。
编程模型和延迟计算
RDD 代表的是分布式数据形态,因此,RDD 到 RDD 之间的转换,本质上是数据形态上的转换(Transformations)。
在 RDD 的编程模型中,一共有两种算子,Transformations 类算子和 Actions 类算子。 开发者需要使用 Transformations 类算子,定义并描述数据形态的转换过程,然后调用 Actions 类算子,将计算结果收集起来、或是物化到磁盘。
在这样的编程模型下,Spark 在运行时的计算被划分为两个环节。
- 基于不同数据形态之间的转换,构建计算流图(DAG,Directed Acyclic Graph);
- 通过 Actions 类算子,以回溯的方式去触发执行这个计算流图。
也即是说开发者调用的各类 Transformations 算子,并不立即执行计算,当且仅当开发者调用 Actions 算子时,之前调用的转换算子才会付诸执行。在业内,这样的计算模式有个专门的术语,叫作“延迟计算”(Lazy Evaluation)。
Spark 有很多算子,做了简单的分类: