这是我参与「第四届青训营 」笔记创作活动的第2天 首先学习了shuffle的概念和shuffle的基本过程,然后学习了Spark中常用的shuffle算子,然后学习了shuffle过程,最后学习了push shuffle。 shuffle的运行过程: 在Mapper中的shuffle 1.当MapTask获取到Split之后按行读取数据 2.每读取一行调用一次map方法 3.每一行经过map方法处理以后,会产生一个或者多个key-value结果 4.Key-value的数据会暂时存到一个环形的缓冲区,这个缓冲区维系在内存中。 5.在缓冲区中会对数据进行分区-partition, 排序-sort, 合并-combine操作 6.当缓冲区使用在达到阈值(已使用缓冲区/缓冲区的总量,默认是0.8),将缓冲区的数据写到当前的磁盘中(spill—溢写),保存数据的格式—溢写。 7.对于单个溢写文件而言,里面的数据是分好区排好序的,但是对于整体所有的溢写文件而言是无序的。 8.等到所有的数据写完,会将所有的溢写文件进行一次合并(merge),合并到一个新的分区并且排序的文件中 9.再最终合并的时候,溢写文件个数<=3,那么合并完成之后会再执行一次Combinaer 在这个过程中需要注意的问题: 1. 当产生溢写的时候,缓冲区最后残留的数据会flush到最后一个溢写文件中 2.Spill理论上默认是80M,但是要考虑序列化以及最后的冲刷等因素 3.不能凭借一个MapTask处理的切片大小来衡量MapTask之后的输出数据的多少 4.每一个切片对应一个MapTask,每一个MapTask对应一个缓冲区 5.缓冲区本质上是一个字节数组 6.缓冲区又叫环形缓冲区,好处在于可以重复利用同一块地址的缓冲区 7.阈值的作用是避免Spill过程产生阻塞 8.merge过程可能不会发生 Reduce中的shuffle: 1.ReduceTask启动多个后台线程发起HTTP请求抓取数据----fetch 2.当前的ReduceTask值抓取对应分区的数据 3.RedcueTask从不同的MapTask上抓取了大量的数据,然后对这些数据进行merge(因为每个MapTask中合并的文件中有各个分区的数据) 4.在merge过程中,会对数据进行一次排序,保证当前分区中的数据有效(在这之后会进行一次分组过程) 5.Merge之后数据要进行一次分组(group),将相同的键所对应的值放到一个ArrayList 6.将ArrayList传递到Reducer中,Reducer将ArrayList转化为一个迭代器传到Reduce方法中 在Reduce中需要注意: 1.fetch的线程数量默认为5个 2.ReduceTask在启动的时候有一个阈值,这个阈值时表示有几个MapTask 3.执行完成之后就要启动ReduceTask,阈值默认时0.05(当有5%的mapTask执行完成之后,启动ReduceTack) 4.merge因子是10(默认十个合一个);
那么Shuffle调优就很重要的,主要有以下的方式: Reduce阶段: 1.增加fetch线程的数量 2.减小reduceTask的阈值—尽量不要动 3.调大merge因子 Mapper阶段: 1.调大缓冲区。建议在250—400M 2.指定combiner减少数据量 3.压缩数据以减少网络传输过程中的时间消耗(这种方式实际上是在网络和内存之间进行了取舍)