spark-shuffle
我们来先说一下shuffle,shuffle就是数据从map task到reduce task的过程。
shuffle过程包括两部分:shuffle write shuffle read,shuffle write发生在数据的准备阶段也就是map task,shuffle readf发生数据的拷贝阶段 也就是reduce task阶段,
shuffle的性能好坏影响着整个集群的性能。
spark-shuffle 的依据为宽依赖:
也就是多个子rdd的一个partition 共同依赖一个父的RDD的一个partition
spark-shuffle
hashshuffleManage的运行原理:
在spark 2.x把hashshuffleManager给弃用了,hashshuffleManage的运行原理:假如我们的一个Executor中又一个cpuCore,我job中含有4个maptask和3个reduce task,我们的Executor执行的我们的map task 的时候会把内存进行按reduce的个数进行分割,分割成一个一个bucket,然后再把数据写进相应的bucket中,当bucket的缓存达到临界值时,在把数据刷到磁盘中生成一个blockshufflefile文件,这样一个maptask就会产生3个小文件,然后我们的reduce task到相应的Executor中找的相应的blockshufflefile进行拷贝数据,形成的新的shffleRDD,然后在执行我们后面的逻辑算子形成mapPartitionRDD。
这种模式:明显的就会产生很多的小文件,maptask就会产生3个小文件 4*3=12个小文件,小文件的产生不利于集群的运行。
后来对这种模式进行了优化:我引入了consolidation机制,引入了一个shuffle group的概念,假如我们的一个Executor中有多个cpuCore,同时执行一批maptask,同样的maptask会把我们的内存按照reduce的个数进行分割成一个一个bucket,同样每个bucket都会产生一个文件。当第一批的maptask执行完之后,下一批的maptask执行的时候,恢复用上一个批次的bucket,同样把数据写入到对应的磁盘文件中去,这样就会减少文件的个数,对系统的性能有很大的提升。
sort-based shuffleManager
有两种模式。一个普通的运行机制和一个bypass运行机制
普通的运行机制:
就是我的maptask运行的数据会写入我内存数据结构中,此时根据不同的shuffle算子,可能选用不同的数据结构。如果是reduceByKey这种聚合类的shuffle算子,那么会选用Map数据结构,一边通过Map进行聚合,一边写入内存;如果是join这种普通的shuffle算子,那么会选用Array数据结构,直接写入内存。接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。在溢写到磁盘文件之前,会先根据key对内存数据结构中已有的数据进行排序。排序过后,会分批将数据写入磁盘文件。一个task将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并,这就是merge过程,此时会将之前所有临时磁盘文件中的数据读取出来,然后依次写入最终的磁盘文件之中。此外,由于一个task就只对应一个磁盘文件,也
就意味着该task为下游stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset。
SortShuffleManager由于有一个磁盘文件merge的过程,因此大大减少了文件数量。比如第一个stage有50个task,总共有10个Executor,每个Executor执行5个task,而第二个stage有100个task。由于每个task最终只有一个磁盘文件,因此此时每个Executor上只有5个磁盘文件,所有Executor只有50个磁盘文件
(磁盘文件数量 = 上游stage的task数量)。
bypass运行机制的触发条件如下:
shuffle map task数量小于spark.shuffle.sort.bypassMergeThreshold参数的值。
不是聚合类的shuffle算子(比如reduceByKey)。
此时task会为每个下游task都创建一个临时磁盘文件,并将数据按key进行hash然后根据key的hash值,将key写入对应的磁盘文件之中。当然,写入磁盘文件时也是先写入内存缓冲,缓冲写满之后再溢写到磁盘文件的。最后,同样会将所有临时磁盘文件都合并成一个磁盘文件,并创建一个单独的索引文件。该过程的磁盘写机制其实跟未经优化的HashShuffleManager是一模一样的,因为都要创建数量惊人的磁盘文件,只是在最后会做一个磁盘文件的合并而已。因此少量的最终磁盘文件,也让该机制相对未经优化的HashShuffleManager来说,shuffle read的性能会更好。
而该机制与普通SortShuffleManager运行机制的不同在于:第一,磁盘写机制不同;第二,不会进行排序。也就是说,启用该机制的最大好处在于,shuffle write过程中,不需要进行数据的排序操作,
也就节省掉了这部分的性能开销。