站在算子角度理解spark分区策略

目录

一、概述

二、从算子角度理解spark分区

1.Source算子

2.Transformation算子

①repartition&coalease

②groupby & groupbykey &partitionby(new HashPartitioner(num)) & reducebykey... & repartitionAndSortWithinPartitions(new HashPartitioner(10)) & join...

③sortby & sortbykey & partitionby(new RangePartitioner(num,rdd)) &  repartitionAndSortWithinPartitions(new RangePartitioner(num,rdd))

3.Action算子


一、概述

       首先,所谓的分区策略,我的理解就是让数据去往哪里。看了很多网上讲spark分区策略,虽然知道了spark有defaultPartitioner、HashPartitioner、RangerPartitioner,但是回到实际工作中还是很懵,比如:啥时候会用到分区策略?用到的时候具体使用的那种策略呢?于是乎,小研究了下,在此总结一下。

二、从算子角度理解spark分区

1.Source算子

       一般在日常的工作中,source算子大多数是从例如hdfs、mysql、本地文件等获取数据,这时候数据去往那个分区和分区策略基本没有关系,而是取决于外部的这些系统,比如读取hdfs文件,是根据blocksize以及你设置的分区大小,来计算分区数,然后按照block去读取数据,这个时候数据在哪个分区取决于它属于哪个block;再比如mysql,spark读取mysql一般是单并行度读取,如果是多并行度,数据去往哪个分区取决于你设置的条件;

2.Transformation算子

      Transformation算子因为算子的不同分区策略也有所不同,但是总结分为以下几类:

①repartition&coalease

       repartition底层是调用开启shuffle的coalease(不讨论不开启shuffle的coalease),当调用他们时,无论是否是key/value类型数据,都是遍历上游算子每个分区中的数据,轮询放入下游算子分区中,放入的时候下游算子的初始分区id是随机的,随后依次加1,源码如下:

②groupby & groupbykey & partitionby(new HashPartitioner(num)) & reducebykey... & repartitionAndSortWithinPartitions(new HashPartitioner(10)) & join...

     这些算子底层都是使用的HashPartitioner,举几个例子:

def groupBy[K](
      f: T => K,
      numPartitions: Int)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] = withScope {
    groupBy(f, new HashPartitioner(numPartitions))
  }

def groupByKey(): RDD[(K, Iterable[V])] = self.withScope {
    //defaultPartitioner底层也是使用的HashPartitioner
    groupByKey(defaultPartitioner(self))
  }

def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD[(K, V)] = self.withScope {
    reduceByKey(new HashPartitioner(numPartitions), func)
  }

//join,cartesian,intersection底层都是cogroup实现的
def cogroup[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))] = self.withScope {
    cogroup(other, defaultPartitioner(self, other))
  }

       从groupby可以看出,不仅key/value数据可以使用HashPartitioner,不是key/value的数据也可以使用,虽然底层是将一条数据作为key,然后调用的groupbykey;

③sortby & sortbykey & partitionby(new RangePartitioner(num,rdd)) &  repartitionAndSortWithinPartitions(new RangePartitioner(num,rdd))

      sortby底层是sortbykey,但是其应用的是RangePartitioner

def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.length)
      : RDD[(K, V)] = self.withScope
  {
    val part = new RangePartitioner(numPartitions, self, ascending)
    new ShuffledRDD[K, V, V](self, part)
      .setKeyOrdering(if (ascending) ordering else ordering.reverse)
  }

        RangePartitioner的源码还没有读过,但是从测试上来说,相同key还是会被放在同一分区中,他所谓说的尽量均衡应该是指不同key;HashPartitioner是根据key值得hash值%numPartition,从这里来说HashPartitioner可能会更容易造成数据倾斜;

3.Action算子

        action算子就没有分区策略之说了,要不就是返回给driver端,要不就是写入到外部系统了

猜你喜欢

转载自blog.csdn.net/m0_64640191/article/details/129711861