概述
MapTask是MapReduce程序map阶段执行的具体任务,上层受MRAppMaster协调调度;内部基于MapContext管理各个组件。其主要功能包括:
- 调用输入组件读取数据
- 调用Mapper执行逻辑
- 调用输出组件写环形缓存
- 执行排序、合并、溢写
- 文件合并
调用关系
程序入口为:
org.apache.hadoop.mapred.YarnChild#main()
调用关系:
核心类说明
YarnChild
入口类,通过其main()方法启动独立进程。内部主要是创建了map阶段的核心类MapTask,并调用起来其run(),真正开启map阶段的执行。
MapTask
Map任务的核心类,初始化基本组件与MapContextImpl环境上下文,并调用Mapper主逻辑,即run()。
Mapper
核心方法为run(),封装循环处理每条数据的完整流程,并基于模板方法设计模式让用户定义map()环节,扩展程序。
核心代码:
public void run(Context context) throws IOException, InterruptedException {
setup(context);
try {
// 调用context入口,具体逻辑由context结合内部组件实现
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
} finally {
cleanup(context);
}
}
MapContextImpl
Map任务的上下文对象,封装其他组件的调用,提供统一入口。比如在Mapper中使用到的context.nextKeyValue()、context.getCurrentKey()、context.getCurrentValue(),其实际的功能实现一般由很多组件参与工作,复杂性也会很高。对Mapper而言并不需要关心其实现细节,只需要通过contex入口获取处理流程中的结果即可。
可见,通过MapContextImpl封装了各个组件的调用,屏蔽了诸多细节,并提供统一的调用入口。它实际是一个中间层,管理维护诸多组件,解耦了调用者与具体的组件。
NewTrackingRecordReader LineRecordReader
输入组件,读取数据。
NewOutputCollector
输出组件。
MapOutputBuffer
维护环形缓冲区,与spillThread协调工作。
SpillThread
和写入线程协同工作,基于锁控制,类似生产-消费模型:写入线程写缓冲区超过80%,唤醒溢写线程;缓冲写满写入线程会阻塞;溢写线程完成溢写,唤醒写入线程。
溢写线程主要功能:内存排序(快速排序)、局部聚合即Combine、写磁盘包括文件和索引、文件合并(归并排序)。
一些文件的合并即mergeParts(),其内部调用了工具类Merger.merge()、Merger.writeFile。