Spark MapOutputTracker原理

运行架构

MapOutputTracker是基于Master/Slave的架构,Master(Driver)负责存储当前Application上所有Shuffle的Map输出元数据信息,而Slave(Executor)可以通过rpc对Master上的Map输出状态信息进行查询。

注册Shuffle

在DAGScheduler使用createShuffleMapStage方法为当前的ShuffleDependency创建对应的ShuffleMapStage时,最后会调用MapOutputTracker.registerShuffle方法注册当前的shuffle,用于保存ShuffleMapStage上所有分区的MapStatus。

def registerShuffle(shuffleId: Int, numMaps: Int) {
  if (mapStatuses.put(shuffleId, new Array[MapStatus](numMaps)).isDefined) {
    throw new IllegalArgumentException("Shuffle ID " + shuffleId + " registered twice")
  }
  // add in advance
  shuffleIdLocks.putIfAbsent(shuffleId, new Object())
}

注册Map输出

当某个ShuffleMapStage运行完成,那么会调用MapOutputTracker.registerMapOutputs方法,将当前ShuffleMapStage中每个分区的计算结果(这些结果并不是真实的数据,而是这些数据所在的位置、大小等元数据信息)进行保存,并增加纪元号。这样依赖该ShuffleMapStage的其他ShuffleMapStage或ResultStage就可以通过这些元数据信息获取其需要的数据。

def registerMapOutputs(shuffleId: Int, statuses: Array[MapStatus], changeEpoch: Boolean = false) {
  mapStatuses.put(shuffleId, statuses.clone())
  if (changeEpoch) {
    incrementEpoch()
  }
}

如果执行器自己存储block(没有开启外部shuffle服务),并且如果执行器丢失导致所有相关的所有shuffle blocks丢失、或者执行器所在slave丢失,或者其他原因导致FetchFailed发生,在这种情况下,我们会假定所有与执行器相关的数据都已经丢失。这时就会移除当前Stage与此执行器相关的所有输出,并调用MapOutputTracker.registerMapOutputs方法更新当前ShuffleMapStage相关的信息。

获取Map输出状态

在BlockStoreShuffleReader中,会调用mapOutputTracker.getMapSizesByExecutorId方法获取一组二元组序列Seq[(BlockManagerId, Seq[(BlockId, Long)])],第一项代表了BlockManagerId,第二项描述了存储于该BlockManager上的一组shuffle blocks。

  1. 首先查看本地缓存中是否有shuffle数据,如果没有则从远程拉取;
  2. 数据结构fetching存储了当前正在fetch的shuffleId,如果fetching列表中包含了需要获取的shuffle,那么当前线程阻塞等待;否则,将当前的shuffle加入到fetching列表中。
  3. 接着调用askTracker方法,向MapOutputTrackerMaster发送GetMapOutputStatuses消息,并阻塞等待结果。
  4. MapOutputTrackerMaster接收到该消息后,会调用getSerializedMapOutputStatuses方法,查询本地记录shuffle对应的Map输出状态。
    • 在获取的过程中需要为每个shuffleId分配一个分段锁,因为这里支持并发调用,同一时间有多个线程需要获取同一个shuffleId对应的输出,所以需要保证Map元数据信息只序列化或者广播一次。所以在获取锁之前和得到锁之后都需要再次查询一下缓存,可能有其他线程已经缓存了MapStatus。
    • 如果缓存还是为空,则需要将MapStatus序列化或者包装为Broadcast。对于序列化还是广播,通过比较序列化后的结果大小是否超出spark.shuffle.mapOutput.minSizeForBroadcast,默认值为512K。
    • 序列化完成后,将此结果进行缓存,并向MapOutputTrackerWorker返回结果。
  5. MapOutputTrackerWorker的askTracker接收到返回的结果后结束阻塞,将数据反序列化并返回。
  6. 最后根据执行的分区范围[startPartition, endPartition]将返回的结果Array[MapStatus]转换成Seq[(BlockManagerId, Seq[(BlockId, Long)])]。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值