什么是RDD

  1. RDDResilient Distributed Dataset 叫做弹性分布式数据集,是Spark中最基本的数据抽象(在Spark操作数据都需要先放到RDD里面,然后再操作RDD)。<br /> Spark是做数据的分析计算的,分析RDD里面的数据<br /> 在代码中是一个抽象类,它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。<br /> 弹性表示RDD将来很容易的进行各种转换,将来数据也可以在不同的节点进行传输.<br /> 分布式表示运行的时候可以并行运算.<br /> 数据集表示可以当做集合,要比Scala的集合强很多.

RDD 的 5 个主要属性(property)

• A list of partitions

多个分区. 分区可以看成是数据集的基本组成单位.
对于 RDD 来说, 每个分区都会被一个计算任务处理, 并决定了并行计算的粒度.
用户可以在创建 RDD 时指定 RDD 的分区数, 如果没有指定, 那么就会采用默认值. 默认值就是程序所分配到的 CPU Coure 的数目.
每个分配的存储是由BlockManager 实现的. 每个分区都会被逻辑映射成 BlockManager 的一个 Block, 而这个 Block 会被一个 Task 负责计算.

• A function for computing each split

计算每个切片(分区)的函数.
Spark 中 RDD 的计算是以分片为单位的, 每个 RDD 都会实现 compute 函数以达到这个目的.

• A list of dependencies on other RDDs

与其他 RDD 之间的依赖关系
RDD 的每次转换都会生成一个新的 RDD, 所以 RDD 之间会形成类似于流水线一样的前后依赖关系. 在部分分区数据丢失时, Spark 可以通过这个依赖关系重新计算丢失的分区数据, 而不是对 RDD 的所有分区进行重新计算.

• Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)

对存储键值对的 RDD, 还有一个可选的分区器.
只有对于 key-value的 RDD, 才会有 Partitioner, 非key-value的 RDD 的 Partitioner 的值是 None. Partitiner 不但决定了 RDD 的本区数量, 也决定了 parent RDD Shuffle 输出时的分区数量.

• Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)

存储每个切片优先(preferred location)位置的列表. 比如对于一个 HDFS 文件来说, 这个列表保存的就是每个 Partition 所在文件块的位置. 按照“移动数据不如移动计算”的理念, Spark 在进行任务调度的时候, 会尽可能地将计算任务分配到其所要处理数据块的存储位置.

RDD特点

弹性

1.存储的弹性:内存与磁盘的自动切换,Spark为了加快运算,理论上所有的数据都是缓存到内存里面,所以Spark非常的吃内存.一般服务器内存一般都至少32个G起步,如果内存不够用的话会自动给数据溢写到磁盘里面,这样执行的效率会下降一些,但是能保证Spark能够继续进行运算而不会因为内存不足而罢工.等待内存足够多的时候又会给磁盘的数据读取到内存里面这样运算速度又加快了.
2.容错的弹性:数据丢失可以自动恢复,数据在计算的过程中有可能会丢失,比如说第一个RDD经过Map的转换生成第二个RDD,然后接着某些操作转换生成第三个RDD,比如说在计算第三个RDD的时候有三个分区,因为某个分区出了问题,计算丢失了,那么会重新去上一个RDD里面获取一遍.
3.计算的弹性:计算出错重试机制,将来分布式多个机器都会跑任务,有可能会出现第一个机器计算后发现内存不够了,或者其它情况, 这时候会进行重试操作,如果重试次数用完. 这个任务将委派给其它的机器节点去执行.
4.分片的弹性:可根据需要重新分片。
前面有100个分区,经过某些操作比日说filter操作,可能很多分区里面的数据都过滤完了,可能只剩下3个分区里面有数据,其它分区都是空的数据,这些空的分区也会占用cpu资源,此时就浪费资源了.这个时候可以对数据进行重新分片,比如说给这个数据分配10个分区,让数据进行接下来的操作,剩下的90个分区就释放出来了.

可分区,并行计算

  1. 说白了就是对读取的后的数据进行合理的分区,让我们的分布式并行的操作能够进行下去.<br />![](https://cdn.nlark.com/yuque/0/2020/png/350923/1608711882886-b4409190-d1d1-4069-8bfe-368698f79dac.png#align=left&display=inline&height=145&margin=%5Bobject%20Object%5D&originHeight=145&originWidth=347&size=0&status=done&style=none&width=347)

不可变

  1. RDD 是只读的,要想改变 RDD 中的数据,只能在现有 RDD 基础上实例化一个新的RDD对象.原来的RDD不会有任何的变化.<br />**RDD 的操作算子包括两类,**<br />• 一类叫做**transformation**,它是用来将 RDD 进行转化,从一个RDD转换成另外一个RDD<br />• 另一类叫做**action**,它是用来触发 RDD 进行计算,得到 RDD 的相关计算结果或者 保存 RDD 数据到文件系统中.

依赖(血缘)

RDDs 通过操作算子进行转换,转换得到的新 RDD 包含了从其他 RDDs 衍生所必需的信息,RDDs 之间维护着这种血缘关系,也称之为依赖。
如下图所示,依赖包括两种,
• 一种是窄依赖,RDDs 之间分区是一一对应的,
• 另一种是宽依赖,下游 RDD 的每个分区与上游 RDD(也称之为父RDD)的每个分区都有关,是多对多的关系。
RDD概述和特点 - 图1

缓存

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

checkpoint

虽然 RDD 的血缘关系天然地可以实现容错,当 RDD 的某个分区数据计算失败或丢失,可以通过血缘关系重建。但是对于长时间迭代型应用来说,随着迭代的进行,RDDs 之间的血缘关系会越来越长,一旦在后续迭代过程中出错,则需要通过非常长的血缘关系去重建,势必影响性能。为此,RDD 支持checkpoint 将数据保存到持久化的存储中,这样就可以切断之前的血缘关系,因为checkpoint 后的 RDD 不需要知道它的父 RDDs 了,它可以从 checkpoint 处拿到数据。