Shuffle模块详解

来源:互联网 发布:淘宝差评被卖家骚扰 编辑:程序博客网 时间:2024/06/03 12:54

Shuffle过程即把数据打乱后重新汇聚到不同节点的过程

7.1 Hash Based Shuffle Write

每个ShuffleMapTask根据key的哈希值计算出每个key需要写入的Partition,然后把数据单独写入一个文件,下游的ShuffleMapTask或者ResultTask便会读取此文件进行计算

7.1.1 Basic Shuffle Write实现原理

val manager=SparkEnv.get.shuffleManager //创建ShuffleManager(Hash和Sort BasedShuffle)

创建Hash Based ShuffleManager

writer=manager.getWrite[Any,Any](dep.shuffleHandle,partitionId,context)(HashShuffleWrite和SortShuffleWriter)

得到Hash Based ShuffleWriter

writer.write(rdd.iterator(partition,context).asInstanceOf[Iterator[_<:Product2[Any,Any]]])执行rdd,并将结果写入文件系统

Rdd.iterator进行rdd计算,ShuffleDependency定义Aggregator是够做Map端的聚合,FileShuffleBlockManager.forMapTask()写入结果

写入完成后会将元数据信息写入MapStatus,会被保存在MapOutputTrackerMaster中

writers.numPartitions返回下游Partition数量(Task数量),每个Partition对应一个文件,文件名称shuffle_+shuffleId+_mapId+_reduceId

return writer.stop(success=true).get关闭writer并将计算结果返回

 

7.1.3 Shuffle Consolidate Writer

spark.shuffle.consolidateFiles设置为true,目的减少shuffle过程中产生的文件,对于运行在同一个Core的Shuffle Map Task而言,第一个Shuffle Map Task会创建一个文件,之后的会将数据直接追加到文件上,具体的实现细节在FileShuffleBlockManager.forMapTask.writers实现

FileShuffleBlockManager.ShuffleFileGroup为文件组,文件组中的每个文件对应一个partition或者下游的Task

blockManager.getDiskWriter为每个文件创建DiskBlockObjectWriter,可直接向一个文件写入数据

 

7.2 Sort Based Write(将所有数据写入一个文件,同时生成Index文件,Reducer利用此Index文件获取需要处理的数据)

SortShuffleManager

ShuffleMapTask会按照key对应的PartitionID进行Sort,其中同一个Partition的key不会sort

SortShuffleWriter的核心功能实现:

1)对于每个Partition创建一个scala.Array存储它所包含的key/value对,如果Array的大小超过阈值则写入外部存储,此文件的开头会记录该Partition的ID以及该文件保存了多少个数据条目
2)将所有写入外部存储的文件进行归并排序

3)生成最后的数据文件时同时生成Index索引文件

 

7.3 Shuffle Read

每个Stage的上边界要么需要从外部存储读取数据,要么需要读取上一个Stage的输出;下边界则要么写入文件系统(ShuffleMap Task),要么输出结果(Result Task)

7.3.1 整体流程

ShuffledRDD.compute()->ShuffleManager.getReader()->ShuffleReader.read()(ShuffleReader均是HashShuffleReader实现)->BlockStoreShuffleFetcher.fetch()会获得数据->MapOutputTracker.getServerStatuses获得数据的元数据信息->MapOutputTrackerMasterActor发送请求(MapOutputTracker.askTracker())->元数据信息保存在Seq[BlockManagerId,Seq[(BlockId,Long)]]->ShuffleBlockFetcherIterator根据数据本地性原则进行数据获取->若数据在本地则BlockManager.getBlockData()对于Shuffle数据则调用ShuffleManager.ShuffleBlockManager.getBlockData();否则如果数据在其他Executor上时,若用户使用spark.shuffle.blockTransferService是netty,则通过NettyBlockTransferService.fetchBlocks获取,如果使用nio,则通过NioBlockTransferService.fetchBlocks获取

 

7.3.2 数据读取策略的划分

ShuffleBlockFetchIterator.splitLocalRemoteBlocks确定划分数据的读取策略,如果数据在本地,则可以直接从BlockManager读取,若在其他Executor上,则需要网络读取

1)每次最多启动5个线程到最多5个节点上读取数据

2)每次请求的数据大小不超过spark.reducer.maxMbInFlight的五分之一

 

7.5.3 本地读取

在ShuffleBlockFetcherIterator.splitLocalRemoteBlocks中调用fetchLocalBlocks负责本地Block的获取,将本地Block列表存入localBlocks(BlockManager.getBlockData),其中会判断数据是否为shuffle数据,若为shuffle数据则ShuffleManager.getBlockData,对于Hash Based Shuffle而言,其ShuffleBlockManager即为FileShuffleBlockManager有两种情况,一种是consolidateFile(根据Map ID和Reduce ID获得FileGroup的一个文件,然后根据文件的offset和size读取数据);否则知己而通过ShuffleBlockID读取整个文件即可;而对于SortBased Shuffle,通过索引文件获取数据块在数据文件中的具体位置信息即IndexShuffleBlockManager.getBlockData

 

7.5.4 远程读取

分别为NettyBlockTransferService.fetchBlocks()和NioBlockTransferService.fetchBlocks()

ShuffleBlockFetcherIterator.sendRequest()向远程节点发起读Block请求,然后NettyBlockTransferService.fetchBlocks()->OneForOneBlockFetcher->TransportClient->NettyBlockRpcServer最终传导远程节点的BlockManager.getBlockData

 

7.6性能调优

7.6.1 spark.shuffle.manager默认是sort based shuffle

7.6.2 spark.shuffle.spill默认是true即指定shuffle过程中如果内存中的数据超过阈值spark.shuffle.memoryFraction设置将部分数据临时写入外部存储

7.6.3 spark.shuffle.memoryFraction(设置内存写外存的阈值)和spark.shuffle.safetyFraction(降低实际Shuffle需要的内存值)

7.6.4spark.shuffle.sort.bypassMergeThreshold用于设置Reducer的partition数目少于多少事,sort based shuffle内部不在使用归并排序,而是直接写入单独文件

在GC严重或者内存紧张时适当降低此值

7.6.5 spark.shuffle.blockTransferService默认是netty

7.6.6 spark.shuffle.consolidateFiles默认是false

7.6.7 spark.shuffle.compress默认都是true,设置Shuffle过程中是否对Shuffle数据进行压缩,如果网络是瓶颈,则设置为true,如果是CPU计算密集型应用则设置false

Spark.shuffle.spill.compress中间结果在spill到本地磁盘进行压缩,将中间结果取回进行merge时进行压缩,Disk IO成为瓶颈时,true更合理,如果是SSD,则设置为false

7.6.8spark.reducer.maxMbInFlight限制Reducer Task向其他Executor请求Shuffle数据的最大内存数,默认是48MB,需要总和考虑网卡带宽和内存
原创粉丝点击