Spark的Shuffle原理(一):HashShuffle

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Oeljeklaus/article/details/81773219

01.HashShuffle相关知识

    Spark Shuffle类似于MapReduce的过程,在Spark 的1.0版本以前,Spark采用的是Hash Shuffle,与MapReduce不同的是,Hash Shuffle没有排序过程。Shuffle阶段主要发生在宽依赖阶段,什么是宽依赖呢?

    上图中,可以很好的理解宽依赖和窄依赖,对于一般的join、groupByKey等算子都会产生宽依赖。网上流传的一句话:

    宽依赖:可以理解为超生,就是一对多、多对多的关系。

    窄依赖:可以理解为独生子女,就是一对一、多对一的关系。

    针对于Shuffle阶段,一般涉及到调优和性能优化,所以理解Shuffle的过程非常重要。

02.Hash Shuflle V1.0的原理

    本文将结合下图讲解HashShuffle的原理:

    HashShuffle主要分为两个阶段,主要是Shuffle Write和Shuffle Read阶段;在Shuffle的上端,我们可以类似的将这个阶段称之为Map端,在Shuffle的下游,我们可以称这个阶段称以为Reduce端;在ShuffleWrite阶段,Map端主要

是根据Reduce端的Task数量,根据Hash函数取模(结合上图,这个Reduce端Task的数量是3个),将数据分为3份,每一份都有一个bucket来存储小文件;每一个Bucket最后将这些文件写入到本地磁盘的ShuffleBlockFile中,形成一个FileSegement文件;所以产生的文件的数量是MapTask数量*ReduceTask数量;结合上图,这里有4个MapTask,下游有3个ReduceTask,所以产生的4*3=12份数据。

    Shuffle Read阶段,Recude端的Task根据自己的分区号,去上游每一个Bucket拉去数据,然后使用fetch操作,将这些小文件合并成为一个大文件(需要注意的是,这里的文件存放在内存中,有可能内存放不下,这也是后来Spark放弃使用这种Shuffle的原因之一)。

扫描二维码关注公众号,回复: 5306263 查看本文章

02.HashShuffle V1.0的缺点以及优化策略

    上一节分析了HashShuffle V1.0的原理,每一个MapTask阶段都会产生和下游ReduceTask个数相同的小文件和bucket,这样会导致内存需要存储大量的文件的描述符,针对于海量的小文件到磁盘,涉及大量的IO操作,同时由于JVM内存不足也会导致多次GC;在这些文件的传输过程中,会涉及序列化和反序列化的过程,这是比较消耗时间的,在ReduceTask拉去数据处理时,需要将数据存放在内存内,如果文件量足够大,内存无法存储,可能导致OOM错误。

    那么,如何解决上述的问题呢?

    Spark提供了另一个种Shuffle,叫做ConsolidatedShuffle,该Shuffle主要以Executor为单位,进行文件的处理,具体过程如下:

    上图中,每一个Executor产生和下游ReduceTask个数相同的bucket,产生的文件数量是Executor数量*ReduceTask个数;当MapTask阶段写文件到磁盘,就是Executor的Core数量*RecueTask数量writehadler;ConsolidatedShuffle仅仅只是解决了文件数量的问题,在磁盘写入的方面没有很大的优化。

    ConsolidatedShuffle的缺点:

    1.ShuffleRead阶段和V1.0阶段一样,也有OOM问题

    2.在ShuffleWrite阶段,文件刷到磁盘时依旧需要使用大量的I/O操作。

                                                                          

                                                                    

猜你喜欢

转载自blog.csdn.net/Oeljeklaus/article/details/81773219