spark的shuffle过程
(1)shuffle的概述
Shuffle描述着数据从map task输出到reduce task输入的这段过程。因为是分布式存储,reduce task需要跨节点去拉取其它节点上的map task结果。这一过程将会产生网络资源消耗和内存,磁盘IO的消耗。通常shuffle分为两部分:Map阶段的数据准备和Reduce阶段的数据拷贝处理。
(2)hash shuffle
1、普通运行机制
1)运行流程
a、每一个shuffleMapTask将不同结果写到不同的buffer中,每个buffer的大小为32K。buffer起到数据缓存的作用。当内存缓冲填满之后,才会溢写到磁盘文件中去。
b、每一个bucket创建一个block file文件。这个bucket存放的数据就是经过Partitioner操作(默认是HashPartitioner)之后找到对应的bucket然后放进去。
c、resultTask来拉取对应的磁盘小文件。一边拉取一边进行聚合的。每个resultTask都会有一个自己的buffer缓冲,每次都只能拉取与buffer缓冲相同大小的数据,然后通过内存中的一个Reduce进行操作。
2)注意事项
a、buffer起到的是缓存作用,缓存能够加速写磁盘,提高计算的效率;分区器:根据hash/numRedcue取模决定数据由几个Reduce处理,也决定了写入几个buffer中
b、产生的磁盘小文件的个数:M(shuffleMapTask的个数)* R(resultTask的个数)
3)缺点
a、Shuffle前在磁盘上会产生海量的小文件,建立通信和拉取数据的次数变多,此时会产生大量耗时低效的 IO 操作 (因為产生过多的小文件)
b、可能导致OOM,大量耗时低效的 IO 操作 ,导致写磁盘时的对象过多,读磁盘时候的对象也过多,这些对象存储在堆内存中,会导致堆内存不足,相应会导致频繁的GC,GC会导致OOM。由于内存中需要保存海量文件操作句柄和临时信息,如果数据处理的规模比较庞大的话,内存不可承受,会出现 OOM 等问题。
2、合并机制的Hash shuffle
1)一个Executor上有多少个CPU core,就可以并行执行多少个task。而第一批并行执行的每个task都会创建一个shuffleFileGroup,并将数据写入对应的磁盘文件内。Executor的CPU core执行完一批task,接着执行下一批task时,下一批task就会复用之前已有的shuffleFileGroup,包括其中的磁盘文件。也就是说,此时task会将数据写入已有的磁盘文件中,而不会写入新的磁盘文件中。consolidate机制允许不同的task复用同一批磁盘文件,这样就可以有效将多个task的磁盘文件进行一定程度上的合并,从而大幅度减少磁盘文件的数量,进而提升shuffle write的性能。
2)产生小文件的个数:block file=Core*R,Core为CPU的核数,R为Reduce的数量
3)缺点:如果 Reducer 端的并行任务或者是数据分片过多的话则 Core * Reducer Task 依旧过大,也会产生很多小文件。
(3)sort shuffle
SortShuffle的运行机制主要分成两种,一种是普通运行机制,另一种是bypass运行机制。当shuffle map task的数量小于等于spark.shuffle.sort.bypassMergeThreshold参数的值时(默认为200),就会启用bypass机制。
1、普通执行机制
数据会先写入一个内存数据结构中(默认5M),此时根据不同的shuffle算子,可能选用不同的数据结构。如果是reduceByKey这种聚合类的shuffle算子,那么会选用Map数据结构,一边通过Map进行聚合,一边写入内存;如果是join这种普通的shuffle算子,那么会选用Array数据结构,直接写入内存。接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。
1)执行流程
a、shuffle map task 的计算结果会写入到一个内存数据结构里面,内存数据结构默认是5M
b、在shuffle的时候会有一个定时器,不定期的去估算这个内存结构的大小,当内存结构中的数据超过5M时,比如现在内存结构中的数据为5.01M,那么他会申请5.01*2-5=5.02M内存给内存数据结构。即:applyMemory=nowMenory*2-oldMemory
c、 如果申请成功不会进行溢写,如果申请不成功,这时候会发生溢写磁盘。
d、在溢写之前内存结构中的数据会进行排序分区
e、然后开始溢写磁盘,写磁盘是以batch的形式去写,一个batch是1万条数据,
f、map task执行完成后,会将这些磁盘小文件合并成一个大的磁盘文件,同时生成一个索引文件。
g、result task去map端拉取数据的时候,首先解析索引文件,根据索引文件再去拉取对应的数据。
2)总结
a、block file= 2M,一个shuffle map task会产生一个索引文件和一个数据大文件
2、byPass机制
1)触发条件
a、shuffle map task数量小于spark.shuffle.sort.bypassMergeThreshold参数的值。
b、不是聚合类的shuffle算子(比如reduceByKey)。
2)执行流程
a、task会为每个reduce端的task都创建一个临时的内存缓冲和磁盘文件,并将数据按key进行hash然后根据key的hash值将key写入对应的内存缓冲之中
b、内存缓冲写满之后再溢写到磁盘文件,会将所有临时磁盘文件都合并成一个磁盘文件,并创建一个单独的索引文件。
3)与sort shuffle的相比:不会进行排序,没有内存结构缓存数据,启用该机制的最大好处在于,shuffle write过程中,不需要进行数据的排序操作,也就节省掉了这部分的性能开销。