RDD计算方式
RDD的宽窄依赖
窄依赖 (narrowdependencies) 和宽依赖 (widedependencies) 。
窄依赖是指 父 RDD 的每个分区都只被子 RDD 的一个分区所使用 。
宽依赖就是指父 RDD 的分区(父RDD被切分并分发了)被多个子 RDD 的分区所依赖。
这种划分有两个用处:
首先,窄依赖支持在一个节点上管道化执行。例如基于一对一的关系,可以在 filter 之后执行 map 。 其次,窄依赖支持更高效的故障还原。因为对于窄依赖,只有丢失的父 RDD 的分区需要重新计算。 而对于宽依赖,一个节点的故障可能导致来自所有父 RDD 的分区丢失,因此就需要完全重新执行。 因此对于宽依赖,Spark 会在持有各个父分区的节点上,将中间数据持久化来简化故障还原,就像 MapReduce 会持久化 map 的输出一样。 |
SparkExample
步骤 1 :创建 RDD 。上面的例子除去最后一个 collect 是个动作,不会创建 RDD 之外,前面四个转换都会创建出新的 RDD 。因此第一步就是创建好所有 RDD( 内部的五项信息 ) 。
步骤 2 :创建执行计划。Spark 会尽可能地管道化,并基于是否要重新组织数据来划分 阶段 (stage) ,例如本例中的 groupBy() 转换就会将整个执行计划划分成两阶段执行。最终会产生一个 DAG(directedacyclic graph ,有向无环图 ) 作为逻辑执行计划。
步骤 3 :调度任务。 将各阶段划分成不同的 任务 (task) ,每个任务都是数据和计算的合体。在进行下一阶段前,当前阶段的所有任务都要执行完成。因为下一阶段的第一个转换一定是重新组织数据的,所以必须等当前阶段所有结果数据都计算出来了才能继续。
假设本例中的 hdfs://names 下有四个文件块,那么 HadoopRDD 中 partitions 就会有四个分区对应这四个块数据,同时 preferedLocations 会指明这四个块的最佳位置。现在,就可以创建出四个任务,并调度到合适的集群结点上。
Spark数据分区
-
Spark的特性是对数据集在节点间的分区进行控制。在分布式系统中,通讯的代价是巨大的,控制数据分布以获得最少的网络传输可以极大地提升整体性能。Spark程序可以通过控制RDD分区方式来减少通讯的开销。
-
Spark中所有的键值对RDD都可以进行分区。确保同一组的键出现在同一个节点上。比如,使用哈希分区将一个RDD分成了100个分区,此时键的哈希值对100取模的结果相同的记录会被放在一个节点上。
(可使用partitionBy(newHashPartitioner(100)).persist()来构造100个分区)
-
Spark中的许多操作都引入了将数据根据键跨界点进行混洗的过程。(比如:join(),leftOuterJoin(),groupByKey(),reducebyKey()等)对于像reduceByKey()这样只作用于单个RDD的操作,运行在未分区的RDD上的时候会导致每个键的所有对应值都在每台机器上进行本地计算。