spark-3.0.1源码阅读之文件数据计算的补充内容


  之前对计算部分的主要代码进行了分析,但是一些重要的细节没有展开来说,本人思量了一下,在这里对其给出补充.
  这里主要以hadoop为例,说明一下spark的分片处理和shuffle处理,也是参照hadoop的部分,给出对比和解释.

1 数据读入时的分片处理

  由于spark只是作为计算引擎,本身不包含数据的存储功能,所以关于输入数据的分片要么使用数据源的分片功能,要么进行简单的对数据进行划分,这部分内容不会很复杂.
  在之前的文件数据计算的源码阅读中,在val value = sc.textFile(outputDir)这一行并没有打上断点,因为这里所说的hadoop的分片处理并没有使用spark的代码,而是使用hadoop自身的,这里进去可以看到
在这里插入图片描述
  textFile方法使用了默认的分片数,同时hadoopFile的输入参数为TextInputFormat,这个是mapred里的类.

1.1 defaultMinPattions分析

  查看其调用的方法树
在这里插入图片描述
  可见,最终是CoarseGrainedSchedulerBackend的defaultparallelism方法,
在这里插入图片描述
  最终的取值为配置中的spark.default.parallelism的值,如果没有设置,则取总共的core的数目.

1.2 分片数分析

  hadoopFile方法中的核心是创建HadoopRDD,该RDD复写了getPartitions方法,此方法就是获取分片数,也就是spark的分区数.其调用的方法树为在这里插入图片描述
  可见,调用的是传入的参数TextInputFormat的父类的getSplits方法
在这里插入图片描述
  可以看到,根据输入的numSplits,也就是之前的defaultMinPattions的值,先计算了目标分片的大小,同时计算了minSize,接着使用了computeSplitSize方法
在这里插入图片描述
  此方法也很简单,就是取最大值而已.
在这里插入图片描述
  先获取目标分片大小和blockSize的最小值,再和前面计算出的minSizse比较,取最大值即可,得到的就是实际分片的大小,使用文件的总大小除以分片的实际大小就是分片数,也就是最终在spark里的分区数.
  比如这里设置了spark.default.parallelism的值为20,总文件大小为2000M,那么2000M/20=100M,就小于128M(blockSize),取其较小者100M为实际分片大小,2000M/100M=20,即分区数为20.可见,当spark.default.parallelism的值设置的比较大的时候,分区数就会和改值相同.

2 令人迷惑的shuffle

  之所以说这个shuffle总是令人迷惑,因为其目的和过程与shuffle这个名字有些不匹配,或者说容易使人产生疑惑.
  Shuffle的本意是洗牌的意思,洗牌无非是把牌打散使其分布均匀,如果是mapred或spark真的按照shuffle的本意使得要计算的数据被打散分布均匀,那么这一切都失去了意义,因为本来就是要reduce或聚合的,当然是相似的数据越聚集越好,而不是越分散越好.

2.1 mr和spark的计算目的

  Mr的计算目的很明确,第一步就是映射出形如<key,value>的键值对,第二步就是把第一步的键值对做合并,相同的键合起来就可以了.
  相比之下,spark的计算就没有这么清晰的目的,可以仅仅是map计算,也可以是先map计算,再reduce计算,所以没有mr那么严格的计算流程,但是最复杂的计算依然是聚合,也就是mr中的reduce.
  因此,Mr和spark的计算目的本质上是相同的,最终都是为了要进行聚合计算.

2.2 shuffle之于mr和spark

  由于mr和spark的计算目的相同,所以shuffle对于两者的作用本质上也是一样的.
  Mr使用shuffle的目的是在reduce之前就形成<key,Iterator>的形式,这样reduce只需要执行合并的逻辑即可,而spark使用shuffle的目的也是类似的,使得最后的聚合可以直接使用聚合逻辑,而不用考虑之前的一些列操作,比如排序分区等.
  可见,mr和spark的计算其实具体分为三阶段,首先是map,其次是shuffle,最后是reduce,那么shuffle的作用就清楚了.

2.3 mr的shuffle的作用

  如前所述,作为计算的第二阶段,shuffle的作用很明显,那就是执行一系列的计算逻辑使<key,value>的集合变为<key,Iterator>的集合.
  mr的shuffle主要操作有:
  1 map端的shuffle
  Map端的shuffle的操作对象是每个map任务的结果,主要操作有分区,排序,溢写磁盘,合并磁盘分区.
  分区是根据key把map结果再次分类,每个reduce任务对应一个分区,借助环形缓冲区,把数据先排序,在此过程中把相同分区的数据组织在一起,再写入磁盘,在磁盘上进行分区的合并,最终形成一个文件,该文件内包含各个分区,分区内的数据有序.
  可见,每个map任务最重经过shuffle的处理,形成唯一一个最终包含多分区的文件.
  2 reduce端的shuffle
  Reduce端的shuffle操作的对象就很明显了,那就是各个map任务端的shuffle最终形成的包含多个分区的文件.主要操作有拉取,排序,归并分组,形成最终的<key,Iterator>形态.
  Shuffle把每个map的最终合并文件拉取过来,不必等到所有的map端的shuffle结束,只要文件准备就绪,就可以拉取.拉取过来后进行排序,对不同map端的文件内同一分区的数据重新再排序,最后对相同的key进行分组,形成<key,Iterator>,供reduce使用.

2.4 spark的shuffle的作用

  Spark的shuffle最初并不像hadoop那样,是按照分区来进行最终的聚合的.之后由于效率的问题,spark也参照了hadoop的shuffle模式,采用了分区的模式,不同的是没有使用类似环形缓冲区生成溢写文件,之后再合并为一个最终文件的过程,而是每个map任务直接在文件中顺序写分区数据,同时生成一个索引文件来记录每个分区的大小和位置.
  最终,spark的shuffle几乎和hadoop的shuffle一致了,都是基于分区来进行聚合,唯一不同的是期间多生成了一个索引文件.

3 总结

  Spark在读取hdfs文件时,采用了hadoop的mapred的类来进行分区,期间的数据计算中使用shuffle,和hadoop的shuffle几乎一模一样,总结起来就是
  1 分区对于spark来说至关重要,这直接与shuffle有关,同时也与资源的利用率有关
  2 hadoop的shuffle和spark的shuffle基本一致,两者的处理逻辑完全相同,只是过程少有不同而已.
  3 shuffle中的耗时操作明显是拉取文件,hadoop以每次拉取一个为单位,spark以每次拉取两个为单位.
  4 mr的计算健壮性明显更强,只使用了一个环形缓冲区,没有过多的涉及内存计算,而spark则容易出现内存方面的问题,比如oom
  如果不是很在意时间,使用mr绝对是第一选择.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值