1.A list of partitions
RDD是一个由多个partition(某个节点里的某一片连续的数据)组成的的list;将数据加载为RDD时,一般会遵循数据的本地性(一般一个hdfs里的block会加载为一个partition)。总结RDD具有分区性
2.A function for computing each split
一个函数计算每一个分片,RDD的每个partition上面都会有function,也就是函数应用,其作用是实现RDD之间partition的转换。总结:RDD多个分区可以并行计算
3.A list of dependencies on other RDDs
RDD会记录它的依赖 ,依赖还具体分为宽依赖和窄依赖,但并不是所有的RDD都有依赖。为了容错(重算,cache,checkpoint),也就是说在内存中的RDD操作时出错或丢失会进行重算。总结:RDD之间具有依赖性
4.Optionally,a Partitioner for Key-value RDDs
可选项,如果RDD里面存的数据是key-value形式,则可以传递一个自定义的Partitioner进行重新分区,例如这里自定义的Partitioner是基于key进行分区,那则会将不同RDD里面的相同key的数据放到同一个partition里面。总结:RDD元素是key-value类型则可以自定义分区器进行分区
5.Optionally, a list of preferred locations to compute each split on
最优的位置去计算,也就是数据的本地性。总结:RDD操作遵循移动计算而不是移动数据
详细:
RDD源码观看
1,分区列表( a list of partitions)
Spark RDD是被分区的,每一个分区都会被一个计算任务(Task)处理,分区数决定了并行计千算的数量,RDD的并行度默认从父RDD传给子RDD。默认情况下,一个HDFS上的数据分片就是一个 partiton,RDD分片数决定了并行计算的力度,可以在创建RDD时指定RDD分片个数,如果不指定分区数量,当RDD从集合创建时,则默认分区数量为该程序所分配到的资源的CPU核数(每个Core可以承载2~4个 partition),如果是从HDFS文件创建,默认为文件的 Block数。
2,每一个分区都有一个计算函数( a function for computing each split)
每个分区都会有计算函数, Spark的RDD的计算函数是以分片为基本单位的,每个RDD都会实现 compute函数,对具体的分片进行计算,RDD中的分片是并行的,所以是分布式并行计算,有一点非常重要,就是由于RDD有前后依赖关系,遇到宽依赖关系,如reduce By Key等这些操作时划分成 Stage, Stage内部的操作都是通过 Pipeline进行的,在具体处理数据时它会通过 Blockmanager来获取相关的数据,因为具体的 split要从外界读数据,也要把具体的计算结果写入外界,所以用了一个管理器,具体的 split都会映射成 BlockManager的Block,而体的splt会被函数处理,函数处理的具体形式是以任务的形式进行的。
3,依赖于其他RDD的列表( a list of dependencies on other RDDS)
由于RDD每次转换都会生成新的RDD,所以RDD会形成类似流水线一样的前后依赖关系,当然宽依赖就不类似于流水线了,宽依赖后面的RDD具体的数据分片会依赖前面所有的RDD的所有数据分片,这个时候数据分片就不进行内存中的 Pipeline,一般都是跨机器的,因为有前后的依赖关系,所以当有分区的数据丢失时, Spark会通过依赖关系进行重新计算,从而计算出丢失的数据,而不是对RDD所有的分区进行重新计算。RDD之间的依赖有两种:窄依赖( Narrow Dependency)和宽依赖( Wide Dependency)。RDD是 Spark的核心数据结构,通过RDD的依赖关系形成调度关系。通过对RDD的操作形成整个 Spark程序。
RDD有窄依赖和宽依赖两种不同类型的依赖,其中的窄依赖指的是每一个 parent RDD的 Partition最多被 child rdd的一个 Partition所使用,而宽依赖指的是多个 child RDD的Partion会依赖于同一个 parent RDD的 Partition。可以从两个方面来理解RDD之间的依赖关系,方面是RDD的 parent RDD是什么,另一方面是依赖于 parent RDD的哪些 Partion;根据依赖于 parent RDD的哪些 Partion的不同情况, Spark将 Dependency分为宽依赖和窄依赖两种。Spak中的宽依赖指的是生成的RDD的每一个 partition都依赖于父RDD所有的 partiton宽依赖典型的操作有 group By Key, sort By Key等,宽依赖意味着She操作,这是 Spark划分Sae的边界的依据, Spark中的宽依赖支持两种 Shuffle Manager,即 Hash Shuffemanager和 Sortshuffemanager,前者是基于Hash的 Shuffle机制,后者是基于排序的 Shuffle机制。
4,key- value数据类型的RDD分区器( a Partitioner for key- alue RDDS)、控制分区策略和分区数
每个key- alue形式的RDD都有 Partitioner属性,它决定了RDD如何分区。当然,Partiton的个数还决定了每个Sage的Task个数。RDD的分片函数可以分区( Partitioner),可传入相关的参数,如 Hash Partitioner和 Range Partitioner,它本身针对key- value的形式,如果不是key-ale的形式它就不会有具体的 Partitioner, Partitioner本身决定了下一步会产生多少并行的分片,同时它本身也决定了当前并行( Parallelize) Shuffle输出的并行数据,从而使Spak具有能够控制数据在不同结点上分区的特性,用户可以自定义分区策略,如Hash分区等。 spark提供了 partition By运算符,能通过集群对RDD进行数据再分配来创建一个新的RDD。
5,每个分区都有一个优先位置列表( a list of preferred locations to compute each split on)
优先位置列表会存储每个 Partition的优先位置,对于一个HDFS文件来说,就是每个Partition块的位置。观察运行 Spark集群的控制台就会发现, Spark在具体计算、具体分片以前,它已经清楚地知道任务发生在哪个结点上,也就是说任务本身是计算层面的、代码层面的,代码发生运算之前它就已经知道它要运算的数据在什么地方,有具体结点的信息。这就符合大数据中数据不动代码动的原则。数据不动代码动的最高境界是数据就在当前结点的内存中。这时候有可能是 Memory级别或 Tachyon级别的, Spark本身在进行任务调度时会尽可能地将任务分配到处理数据的数据块所在的具体位置。据 Spark的RDD。 Scala源代码函数get Parferredlocations可知,每次计算都符合完美的数据本地性。可在RDD类源代码文件中找到4个方法和1个属性,对应上述所阐述的RDD的五大特性,源代码剪辑如下