关闭

决定Spark RDD分区算法因素的总结

256人阅读 评论(0) 收藏 举报
分类:

RDD在调用引起Shuffle的方法的时候,如果没有显示指定ShuffledRDD的分区,那么会调用Partitioner.defaultPartitioner方法来确定ShuffledRDD的分区,比如RDD.combineByKey:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C)  
  2.     : RDD[(K, C)] = self.withScope {  
  3.     combineByKey(createCombiner, mergeValue, mergeCombiners, defaultPartitioner(self))  
  4.   }  

RDD.groupByKey:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. def groupByKey(): RDD[(K, Iterable[V])] = self.withScope {  
  2.     groupByKey(defaultPartitioner(self))  
  3.   }  

RDD.join:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))] = self.withScope {  
  2.     join(other, defaultPartitioner(self, other))  
  3.   }  


Partitioner.defaultPartitioner代码如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. def defaultPartitioner(rdd: RDD[_], others: RDD[_]*): Partitioner = {  
  2.     val bySize = (Seq(rdd) ++ others).sortBy(_.partitions.size).reverse//从大到小排序  
  3.     for (r <- bySize if r.partitioner.isDefined) {  
  4.       return r.partitioner.get//如果依赖的RDD中存在RDD已经设置了分区,则从设置了分区的RDD中则挑选出分区数最大的RDD.partitioner  
  5.     }  
  6.     if (rdd.context.conf.contains("spark.default.parallelism")) {  
  7.       new HashPartitioner(rdd.context.defaultParallelism)  
  8.     } else {  
  9.       new HashPartitioner(bySize.head.partitions.size)//默认取分区个数最大的RDD作为hashcode  
  10.     }  
  11.   }  
可见默认情况下,ShuffledRDD的分区确定算法为:

1. 如果依赖的RDD中存在RDD已经设置了RDD.partitioner,则从设置了分区的RDD中则挑选出分区数最大的RDD.partitioner

2. 如果依赖的所有RDD都没有设置RDD.partitioner,但是设置了Spark.default.parallelism,那么根据spark.default.parallelism设置创建HashPartitioner,作为ShuffledRDD的分区依据

3. 以上2点都不满足,则从依赖的RDD中,去除分区数最大的RDD的分区个数,创建HashPartitioner,作为ShuffledRDD的分区依据


一个Spark应用可能包含多个Stage,假设Stage1经过Shuffle后生成新的ShuffledRDD1,然后再开始Stage2,但是从Stage2到Stage3的时候,在确定ShuffledRDD2的时候,ShuffledRDD1.partitioner是不是还存在呢?RDD.map是RDD最常调用的方法,RDD.map会创建MapPartitionsRDD,下面看看MapPartitionsRDD的创建:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. def map[U: ClassTag](f: T => U): RDD[U] = withScope {  
  2.     val cleanF = sc.clean(f)  
  3.     new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.map(cleanF))  
  4.   }  

可见MapPartitionsRDD.partitioner为None,由此可见ShuffledRDD1执行完map方法转换之后,ShuffledRDD1的partitioner没有传递到MapPartitionsRDD

为什么呢?

因为进行map操作之后,RDD中的数据已经发生了变化,每个数据如果shuffle的话计算出来的Hash值已经发生了改变,而Hash值确定了RDD中一个元素所在的分区,RDD的每个元素在下一个Stage所在的分区很可能发生了变化,所以默认情况下MapPartitionsRDD.partitioner设置为None,这样即使shuffle前的Stage1和Shuffle后的Stage2的分区个数相同,也需要Shuffle来重新确定RDD中每个元素所在的分区。


假设Shuffle后的RDD依赖多个RDD,比如说CoGroupedRDD,会不会两个RDD都会发生Shuffle呢?下面以CoGroupedRDD为例看一看。CoGroupedRDD.getDependencies的定义如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. override def getDependencies: Seq[Dependency[_]] = {  
  2.     rdds.map { rdd: RDD[_] =>  
  3.       if (rdd.partitioner == Some(part)) {  
  4.         logDebug("Adding one-to-one dependency with " + rdd)  
  5.         new OneToOneDependency(rdd)  
  6.       } else {  
  7.         logDebug("Adding shuffle dependency with " + rdd)  
  8.         new ShuffleDependency[K, Any, CoGroupCombiner](  
  9.           rdd.asInstanceOf[RDD[_ <: Product2[K, _]]], part, serializer)  
  10.       }  
  11.     }  
  12.   }  

可见如果CoGroupedRDD依赖的某个RDD和CoGroupedRDD分区相同,则这个被依赖的RDD就不会进行Shuffle。


0
0
查看评论

Spark RDD系列-------1. 决定Spark RDD分区算法因素的总结

RDD在调用引起Shuffle的方法的时候,如果没有显示指定ShuffledRDD的分区,那么会调用Partitioner.defaultPartitioner方法来确定ShuffledRDD的分区,比如RDD.combineByKey: def combineByKey[C](createComb...
  • u012684933
  • u012684933
  • 2015-11-25 17:51
  • 2958

Spark2.0-RDD分区原理分析

Spark分区原理分析介绍分区是指如何把RDD分布在spark集群的各个节点的操作。以及一个RDD能够分多少个分区。一个分区是大型分布式数据集的逻辑块。 那么思考一下:分区数如何映射到spark的任务数?如何验证?分区和任务如何对应到本地的数据? Spark使用分区来管理数据,这些分区有助于并行...
  • zg_hover
  • zg_hover
  • 2017-06-20 07:54
  • 1608

Spark RDD 分区数详解

基础知识 spark.default.parallelism:(默认的并发数)= 2 当配置文件spark-default.conf中没有显示的配置,则按照如下规则取值: 1、本地模式(不会启动executor,由SparkSubmit进程生成指定数量的线程数来并发):    ...
  • jiangsanfeng1111
  • jiangsanfeng1111
  • 2017-10-10 14:05
  • 582

Spark-RDD 分区

RDD分区在分布式程序中,通信的代价是很大的,因此控制数据分布以获得最少的网络传输可以极大地提升整体性能。所以对RDD进行分区的目的就是减少网络传输的代价以提高系统的性能。RDD的特性在讲RDD分区之前,先说一下RDD的特性。RDD,全称为Resilient Distributed Datasets...
  • sicofield
  • sicofield
  • 2016-03-25 17:58
  • 5981

Spark RDD 内部结构(二) RDD分区

RDD 分区 分区 先回答第一个问题:RDD 内部,如何表示并行计算的一个计算单元。答案是使用分区(Partition)。 RDD 内部的数据集合在逻辑上和物理上被划分成多个小子集合,这样的每一个子集合我们将其称为分区,分区的个数会决定并行计算的粒度,而每一个分区数值的计算都是在一个单独的任务...
  • songsehaiyang
  • songsehaiyang
  • 2017-01-23 11:07
  • 2596

Spark自定义RDD重分区

在某些计算场景中,我们可能需要将两个有关联的数据输入的部分数据,也就是说RDD中的部分数据,需要聚合在同一个partition进行匹配计算,这个时候,我们就需要根据实际的业务需求,自定义RDD重分区。
  • cyony
  • cyony
  • 2017-06-26 14:45
  • 858

判断RDD有多少个分区

为了调优和故障排查,经常有必要知道RDD中有多少个Partition。有如下几个方式可以找到这些信息: 使用Spark web UI查看任务执行和分区情况 当一个stage执行的时候,你可以在Spark UI中查看一个指定stage的分区个数。例如,下面的代码创建了一个有100个元素,4个分区的...
  • sdujava2011
  • sdujava2011
  • 2016-01-28 15:58
  • 2640

Spark重新分区—repartition和coalesce的用法

转载链接:http://blog.csdn.net/u011981433/article/details/50035851 重分区函数:     repartition(numPartitions:Int):RDD[T]     coalesce...
  • u013514928
  • u013514928
  • 2016-10-11 16:36
  • 3201

Spark基础随笔:分区小结

RDD分区的一个分区原则:尽可能是得分区的个数等于集群核心数目 下面我们仅讨论Spark默认的分区个数,这里分别就parallelize和textFile具体分析其默认的分区数 无论是本地模式、Standalone模式、YARN模式或Mesos模式,我们都可以通过spark.default.para...
  • jiangpeng59
  • jiangpeng59
  • 2016-10-08 14:48
  • 8349

Spark开发-RDD分区重新划分

repartition(numPartitions: Int):RDD[T] coalesce(numPartitions: Int, shuffle: Boolean = false):RDD[T]repartition和coalesce是对RDD的分区进行重新划分,repartition只是c...
  • paicMis
  • paicMis
  • 2017-10-09 23:36
  • 186
    个人资料
    • 访问:119820次
    • 积分:2449
    • 等级:
    • 排名:第17827名
    • 原创:114篇
    • 转载:75篇
    • 译文:3篇
    • 评论:12条
    文章分类
    最新评论