Spark执行各种操作的分区数解读

参考资料
https://juejin.im/entry/5a372a9b6fb9a04503102d75
https://dongkelun.com/2018/08/13/sparkDefaultPartitionNums/ //详细记录了不同操作下各个分区的个数

前言

我们这边分区数是按照什么规则呢,今天详细吧这个问题好好看下

分区的数量决定了spark任务的并行度

前提 我们的分区数都是按照默认规则,没有人为改变过分区

分区规则

我们不管是read.csv 还是 textFile 还是spark读取hive的数据,根源还是相当于读取hadoop上面的数据,所以他们的分区规则是一样的。原则上其实都是走的HadoopRDD相关方法。在测试和实验中也都能验证这些先关。(注意:在测试之前看看自己集群的block.size是多大,我们这里是256M真的是把我给坑坏了。)

对于这块的分区规则,我决定不上源码https://juejin.im/entry/5a372a9b6fb9a04503102d75 这片文章有源码先关,这里我只说源码中的几个细节
大家可以比对着源代码看我这块 就是FileInputFormat.getSplits的方法

textFile相关

通过textFile方式生成的rdd
如, val rdd = sc.textFile(“path/file”)
有两种情况:
a、从本地文件file:///生成的rdd,操作时如果没有指定分区数,则默认分区数规则为:
rdd的分区数 = max(本地file的分片数, sc.defaultMinPartitions)
b、从hdfs分布式文件系统hdfs://生成的rdd,操作时如果没有指定分区数,则默认分区数规则为:
rdd的分区数 = max(hdfs文件的block数目, sc.defaultMinPartitions)

源码解释

1、long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits); 中numSplits的相当于是defaultMinPartitions: Int = math.min(defaultParallelism, 2) 这里的defaultParallelism值
由spark.default.parallelism 这个参数决定,在yarn上参数最小是2 也就决定了这个defaultMinPartitions的值最小是2
(这里也有出入,textFile自己也可以去指定)

2、 long minSize = Math.max(job.getLong(org.apache.hadoop.mapreduce.lib.input.
FileInputFormat.SPLIT_MINSIZE, 1), minSplitSize);
这个值默认其实就是1

3、long splitSize = computeSplitSize(goalSize, minSize, blockSize); 这一行代码中点进去相当于
return Math.max(minSize, Math.min(goalSize, blockSize));
来确定splitSize 的值。所以这里就一目了然了。

4、这两行代码相当于是将大文件就行切分,剩余的部分在重新初始化一个数组, 如果小文件是直接初始化一个数组

while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
            String[][] splitHosts = getSplitHostsAndCachedHosts(blkLocations,
                length-bytesRemaining, splitSize, clusterMap);
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                splitHosts[0], splitHosts[1]));
            bytesRemaining -= splitSize;
          }

          if (bytesRemaining != 0) {
            String[][] splitHosts = getSplitHostsAndCachedHosts(blkLocations, length
                - bytesRemaining, bytesRemaining, clusterMap);
            splits.add(makeSplit(path, length - bytesRemaining, bytesRemaining,
                splitHosts[0], splitHosts[1]));
          }

字面解释

1、如果一个目录中只有一个小文件,比如10M,那么他最少还是得有2个分区(在yarn上运行的时候)
2、如果一个目录很大,然后里面有小文件,那么小文件是只占用一个分区的 (这个和源码中的totalSize以及由他生成的goalSize有关系,因为他们决定了splitSize,影响了后续bytesRemaining)/splitSize > SPLIT_SLOP这个值的大小)
3、如果一个目录的大文件就是按照block进行分片的,比如230M,相当于2个分片(128M,102M)

spark读取hive执行sql的分区数

最后说一嘴这一块
执行sql这一块,我发现执行完

session.sql(“select name,count(*) from ceshi.demo group by name”).write.csv("/user/zgh/kkk")

这个以后分区变成了200个,这个和spark的参数spark.sql.shuffle.partitions有关系。他的默认值是200,这里需要注意的是这个参数只对shuffle后的数据起作用,比如sql在做join或者聚合的操作。
如果只是select * 之类不需要聚合的操作这个参数是不起作用的。如果我们还想再没有shuffle的时候给他改变分区的话,我们可以使用repartition方法。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值