Spark2.3.2源码解析: 8. RDD 源码解析 (一) RDD 类分析

全称: 弹性分布式数据集


1)有一个分片列表,就是能被切分,和Hadoop一样,能够切分的数据才能并行计算。

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

2)由一个函数计算每一个分片,这里指的是下面会提到的compute函数。

        Spark中的RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

3)对其他RDD的依赖列表,依赖还具体分为宽依赖和窄依赖,但并不是所有的RDD都有依赖。

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

4)可选:key-value型的RDD是根据哈希来分区的,类似于mapreduce当中的paritioner接口,控制Key分到哪个reduce。

    一个partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个基于范围的RangePartitioner。只有对于key-value的RDD,才会有Partitioner,非key-value的RDD的Partitioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。


5)可选:每一分片的优先计算位置,比如HDFS的block的所在位置应该是优先计算的位置。

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




论文:

https://blog.csdn.net/zhanglong_4444/article/details/84950343

https://blog.csdn.net/zhanglong_4444/article/details/84968347

话不多少直接看源码:

 

 

代码: org.apache.spark.rdd.RDD

 

必须要有sparkcontext

必须要有唯一的 ID  和对应的名称

 

可以进行持久化操作 persist 

cache方法 默认持久化内存 ,实际调用的还是persist方法
def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)

 

设置快照 checkpointRDD (非同步操作)

 

获取依赖关系dependencies

 

 

分区partitions

每个分区都有一个下标 index

 

核心方法: iterator 

logInfo("数据已经持久化过,直接获取或者计算。。。。")
getOrCompute(split, context)

 

 

里面的Left 和Right 方法作用 先进性记录,后续会补全。

----------------- todo -----------------------

 

 

Compute an RDD partition or read it from a checkpoint if the RDD is checkpointing.

 

 

 给定一个rdd , 通过窄依赖,递归获取其祖先, 仅通过一系列狭窄的依赖关系返回与其相关的给定RDD的祖先
 给定一个返回一个rdd依赖, 但并不保证其顺序

 

Map filter, 和FlatMap 实质都是生成一个新的MapPartitionsRDD

 

 

 
val cleanF = sc.clean(f)

 

ClosureCleaner 类中的clean 方法 再里面就,方法就很长了。
这个类的作用是递归清理外围类中无用域,降低序列化的开销,防止不必要的不可序列化异常。 降低网络io,提高executor的内存效率

 MapPartitionsRDD

 

去重 distinct 函数实质上是用的  reduceByKey 函数进行的数据转换

 

重新分区  repartition 和coalesce

repartition(numPartitions:Int):RDD[T]和coalesce(numPartitions:Int,shuffle:Boolean=false):RDD[T]

他们两个都是RDD的分区进行重新划分,repartition只是coalesce接口中shuffle为true的简易实现,(假设RDD有N个分区,需要重新划分成M个分区)

1)、N<M。一般情况下N个分区有数据分布不均匀的状况,利用HashPartitioner函数将数据重新分区为M个,这时需要将shuffle设置为true。

2)如果N>M并且N和M相差不多,(假如N是1000,M是100)那么就可以将N个分区中的若干个分区合并成一个新的分区,最终合并为M个分区,这时可以将shuff设置为false,在shuffl为false的情况下,如果M>N时,coalesce为无效的,不进行shuffle过程,父RDD和子RDD之间是窄依赖关系。

3)如果N>M并且两者相差悬殊,这时如果将shuffle设置为false,父子RDD是窄依赖关系,他们同处在一个Stage中,就可能造成spark程序的并行度不够,从而影响性能,如果在M为1的时候,为了使coalesce之前的操作有更好的并行度,可以讲shuffle设置为true。

总之:如果shuff为false时,如果传入的参数大于现有的分区数目,RDD的分区数不变,也就是说不经过shuffle,是无法将RDDde分区数变多的。
 

 

 

根据权重随机切分: randomSplit

union 函数

实际:

函数 sortBy  实际调用的是sortbykey函数

 

 

groupby 函数

函数: mapPartitions

 

foreach
foreachPartition
collect
toLocalIterator
count

上面提交的时候,实际都会运行run job 方法

reduce

 

saveAsTextFile

toJavaRDD

 

 

只是挑了几个重要的方法

其他方法暂时略,后期会专门对常用的函数做源码分析。。。。。。。。。。。。。。。。

 

val textFile = sc.textFile(args(0))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关推荐
©️2020 CSDN 皮肤主题: 鲸 设计师:meimeiellie 返回首页