Spark编程模型RDD,即弹性分布式数据集的简称。RDD是一个容错的、并行的数据结构,可以让用户显式地将数据映射/存储到磁盘和内存中,并能控制数据的分区。同时,RDD还提供了一组丰富的算子来操作这些数据。RDD是只读的记录分区的集合,只能通过在其他RDD执行确定的转换操作(transformation操作)而创建。RDD本质上是一个内存数据集,在访问RDD时,指针只会指向与操作相关的数据部分。
RDD将操作分为两类:transformation与action。无论执行了多少次transformation操作,RDD都不会真正执行运算,只有当action操作被执行时,运算才会触发。而在RDD的内部实现机制中,底层接口则是基于迭代器的,从而使得数据访问变得更高效,也避免了大量中间结果对内存的消耗。
#RDD是Spark的核心,也是整个Spark的架构基础。
1. RDD是不变的数据结构存储
2. RDD是支持跨集群的分布式数据结构
3. RDD可以根据数据记录的key对结构进行分区
4. 提供了粗粒度的操作,且这些操作都支持分区
5. 它将数据存储在内存中,从而提供了低延迟性
#RDD的特征
RDD总共有五个特征,其中三个基本特征,两个可选特征。
1. 分区(partition):有一个数据分片列表,可以将数据进行划分,切分后的数据能够进行并行计算,是数据集的原子组成部分。
2. 函数(compute):即算子,对于每一个分片都会有一个函数去迭代/计算执行它。
3. 依赖(dependency):每一个RDD对父RDD有依赖关系,源RDD没有依赖,通过依赖关系建立来记录它们之间的血统(关系-lineage)。
4. 优先位置(可选):每一个分片会优先计算位置(prefered location)。即要执行任务在哪几台机器上好一点(数据本地性)。
5. 分区策略(可选):对于key-value的RDD可以告诉它们如何进行分片。可以通过repartition函数进行指定。
#RDD之间的依赖关系(从分区partition的角度来定义依赖关系的)
RDD的依赖关系分为两种模型,一种是窄依赖(narrow dependency)和宽依赖(wide dependency)。
1.窄依赖:父RDD的每一个分区最多被一个子RDD的分区所用,表现为一个父RDD的分区对应于一个子RDD的分区(第一类),或者是多个父RDD的分区对应于一个RDD的分区(第二类),也就是说一个父RDD的一个分区不可对应于一个子RDD的多个分区。
如下图所示,对输入进行协同划分(co-partitioned)的join属于第二类。当子RDD的分区依赖于单个父RDD的分区的时候,分区的结构不会发生改变,如下图中的map,filter等操作,相反的,对于一个子RDD的分区依赖于多个RDD的分区的时候,分区的结构会发生改变,如下图的union操作。
2.宽依赖:宽依赖是值子RDD的每一个分区都要依赖于所有父RDD的所有分区或者多个分区。也就是说存在一个父RDD的一个分区对应着一个子RDD的多个分区。如下图的groupByKey就属于宽依赖。其中宽依赖会出发shuffle操作,下面会详细讲到。
#
创建RDD的几种方式
1.Parallelized Collections(并行化计算一个集合)
2.External Datasets(引用外部数据)
3.RDD经转换操作生成新的RDD
通常将RDD操作分为两种操作,转换(transformation)和执行(action),在默认情况下,spark的所有转换操作都是惰性的(lazy),对于每一个转换得到的RDD结果不会立即计算出结果,只是记下该转换操作的一些基础数据集,可以有多个转换结果,一旦遇到action操作就 会执行之前的所有transformation操作,最后得到结果(spark的作业执行其实就是构建DAG(有向无环图),下面会讲到),所有的RDD被清除,如果下一个JOB中会用到其他JOB中的RDD,会引发该RDD的再次计算,因此,为了避免重新计算,我们可以使用persist或者cache操作进行“持久化”一个RDD到内存当中,也可以缓存到磁盘当中。
RDD对应的控制操作
RDD的控制操作主要包括故障恢复,数据持久化以及数据移除等操作。
1. 故障恢复
对于一个集群,spark会做出两种假设:处理的时间有限;保持数据持久化是外部数据的职责,主要让处理过程中数据保护稳定。Spark基于假设会折中选择方案,基于RDD之间的依赖关系,如果一个RDD坏掉,则会重新执行其父RDD的相应分区,不需要重新执行全部的JOB。
宽依赖的再执行涉及到多个父RDD(因为宽依赖会出发shuffle操作,也就是说宽依赖跨多个stage),从而引发整个JOB重新执行,为了避免这一点,spark会保持Map阶段的中间数据输出的持久,在发生故障时,只需回溯到mapper执行的相应分区即可获取中间数据。
2. RDD持久化
RDD持久化分为主动持久化和自动持久化。自动持久化就是不需要用户调用持久化操作,spark自动保存一些Shuffle操作的中间结果(保存到磁盘中)来避免节点崩溃时重新计算所有的输入。
主动持久化需要用户自己在需要持久化的RDD调用persist操作或者cache操作缓存数据到内存中(默认),持久化的等级选择是通过一个Storage Level对象传递给persist方法进行确定的,Cache方法调用persist()的默认级别是MEMORY_ONLY(内存)。
RDD的数据移除
RDD可以在内存中进行缓存,spark会坚持每一个节点上使用的缓存,如果集群中没有足够的内存时,spark会根据LRU算法(最近最少使用算法,操作系统内存管理章节内容)对数据分区进行删除。
如果想手动删除,可以在指定RDD中调用unpersist方法删除,立即生效。