Spark中的两种shuffle过程原理

Spark

两种Shuffle

在spark1.1以前只有hashshuffle,1.1版本引入了sortshuffle,1.2版本以后默认方式改为sort方式,2.0版本以后移除了hashshuffle。

HashShuffle

  1. 执行原理:

    Map阶段的shuffle是为了下一个stage的task拉取数据作的。

    • 每个Map阶段task把要输出的数据按key进行hash
    • 根据hash得到的值,生成和下一个stage的task数量相同的磁盘文件并写入。
    • 在将数据写入磁盘之前,会先将数据写入内存缓冲中,当内存缓冲填满之后,才会溢写到磁盘文件中去。
  2. 产生文件:

    假设下一个stage有st个task,当前stage有e个exector,每个excutor有t个task,那么一共会产生e*t*st个磁盘文件

  3. shuffleRead:

    通常是一个stage刚开始时要做的事情,把本stage需要的数据从上一个stage阶段shuffle的数据拉进来。在HashShuffle下,shuffleRead只用让每个task从自己的那个文件里拉取数据进缓冲区进行聚合,并且一边拉取一边进行聚合,每次拉取buffer缓冲区大小的数据,再传输到内存中。

  4. 原理图:

在这里插入图片描述

基于Consolidate(合并)机制的HashShuffle

​ 配置spark.shuffle.consolidateFiles为true,默认为false

  1. 执行原理:

    基础的hashShuffle会产生大量的文件,因此优化的HashShuffle对它进行优化。其他不变,在基础HashShuffle写出文件时,上一stage执行的第一批task会为每个下一stage的task创建一个磁盘文件,每个task生成的这些文件称为一个shuffleFileGroup,接下来运行的每个task就不再产生新的文件,而是根据自己的shuffleFileGroup,把数据hash到属于自己组的文件中。

  2. 产生文件:

    假设下一个stage有st个task,当前有cores个cpu核数(每个核运行一个task),那么一共会产生cors*st个磁盘文件

  3. 原理图:

    在这里插入图片描述

HashShuffle的优缺点

  1. 优点
    • 避免排序带来的cpu和内存的开销
  2. 缺点
    • 产生的磁盘文件太多,存在内存、磁盘的开销,同时io操作太耗时。

普通的SortShuffle

​ 在该模式下,数据会先写入一个内存数据结构中,此时根据不同的 shuffle 算子,可能选用不同的数据结构。如果是 reduceByKey 这种聚合类的 shuffle 算子,那么会选用 Map 数据结构,一边通过 Map 进行聚合,一边写入内存;如果是 join 这种普通的 shuffle 算子,那么会选用 Array 数据结构,直接写入内存。接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。

  1. 执行原理:

    • 在写入磁盘之前,会针对key对数据进行sort操作,然后分批写入磁盘,默认的batch大小是一万条,即每次写入一万条数据到一个磁盘文件(一个磁盘文件可能有多批的数据),此时产生的个个溢写文件是临时文件 。注意,排序后并不是直接写入磁盘,而是通过java的BufferedOutputStream写入的,也就是说首先会写入内存缓冲区,缓冲区满之后在溢写到磁盘。
    • 每个task进行分批溢写磁盘之后,会有一个合并操作,将每次溢写产生的临时磁盘文件读取出来以后依次写入同一个文件,也就意味着一个task只会生成一个磁盘文件,同时,该task会给这个文件生成一个索引文件,其中标识了下游各个 task 的数据在文件中的 start offset 与 end offset。即每个task会生成两个文件(数据文件、索引文件)。
  2. 产生文件:

    假设当前stage有n个task,则最终会产生n*2个文件

  3. shuffleread:

    下游stage开始的读取数据阶段时,直接通过索引文件在每个task生成的文件中拉取即可。

  4. 原理图:

    在这里插入图片描述

基于bypass的SortShuffle

​ 当下一个stage的task数较少的情况下,hashShuffle会比sortShuffle方式更快,因为它少了排序开销。当 下一个stage任务数少于配置属性spark.shuffle.sort.bypassMergeThreshold设置的个数时,会启用该机制进行优化。

触发条件:

  • 下一个stage任务数少于配置属性spark.shuffle.sort.bypassMergeThreshold设置的个数
  • 不是聚合类的shuffle算子
  1. 执行原理:

    • 执行采用普通的HashShuffle机制进行,即当前task会为下一stage的每个task都产生一个临时文件(通过缓冲的方式),但是在最后会把这些临时文件合并成对应当前task的一个文件,这对于下一stage的拉取数据更高效。
  2. 产生文件:

    假设当前stage有n个task,则最终会产生n*2个文件

  3. shuffleread:

    下游stage开始的读取数据阶段时,直接通过索引文件在每个task生成的文件中拉取即可。

  4. 原理图:

    在这里插入图片描述

Tungsten Sort Shuffle

​ 这种方式过程和普通的SortShuffle方式一样,但是sort操作时针对序列化后的字节数组指针进行排序的,而不是对原始数据进行排序,而是对二进制数据进行排序,因此算法效率会高很多。但是可以看出它不能适应需要对内容进行聚合的操作。

触发这种Shuffle方式条件比较苛刻:

  1. Shuffle 依赖中不带聚合操作或没有对输出进行排序的要求。
  2. Shuffle 的序列化器支持序列化值的重定位(当前仅支持 KryoSerializer Spark SQL 框架自定义的序列化器)。
  3. Shuffle 过程中的输出分区个数少于 16777216 个
  4. 其他的一些限制

使用哪种sortshuffle的判断流程

  1. 通过 SortShuffleWriter.shouldBypassMergeSort 方法判断是否需要回退到 Hash 风格的 Shuffle 实现机制(bypass机制)
  2. 当该方法返回的条件不满足时,则通过 SortShuffleManager.canUseSerializedShuffle方法判断是否需要采用基于 Tungsten Sort Shuffle 实现机制
  3. 当这两个方法返回都为 false,即都不满足对应的条件时,会自动采用普通运行机制。

三种SortShuffle的优缺点

  1. 普通的SortShuffle会对文件排序,所以会有排序开销,在下一stage阶段task较少的情况下会比较低效。但是它通过合并文件的机制减少了最终的磁盘数量,并且中间文件的数量也比hash方式少,加快了速度,减少了io开销。
  2. bypass机制的SortShuffle针对普通SortShuffle在下一stage阶段task较少的情况下会比较低效的缺点,当满足出发条件时采用hashShuffle的方式进行Shuffle操作,但是最后会把文件合并,减少最终生成的文件数量,提高了shuffleread的效率,并且没有排序操作,提高了少文件数时的速度。
  3. Tungsten的使用存在限制,不能适应带有聚合操作的shuffle,触发条件苛刻,
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值