Hadoop源码分析(2)————MapReduce之MapTask

本文详细介绍了Hadoop中MapTask的工作流程,包括初始化过程、如何处理输入分片、记录读取器的实例化以及Map阶段的数据处理等核心环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MapTask(Hadoop2.7.3)

MapTask.java继承于Task,是hadoop中Map节点主要所做的主要流程。
一般被jvmtask初始化或者在MapTaskAttemptImpl被初始化。其主要流程写在run()方法中。
run()方法主要在YarnChild中被调用(伪分布式或者分布式,如果是在单机模式一般被LocalJobRunning被调)也就是说Map节点都是被Yarn启动的。

@Override
  public void run(final JobConf job, final TaskUmbilicalProtocol umbilical)
          throws IOException, ClassNotFoundException, InterruptedException {
    this.umbilical = umbilical;

    if (isMapTask()) {
      // If there are no reducers then there won't be any sort. Hence the map
      // phase will govern the entire attempt's progress.
      if (conf.getNumReduceTasks() == 0) {
        mapPhase = getProgress().addPhase("map", 1.0f);
      } else {
        // If there are reducers then the entire attempt's progress will be
        // split between the map phase (67%) and the sort phase (33%).
        mapPhase = getProgress().addPhase("map", 0.667f);
        sortPhase = getProgress().addPhase("sort", 0.333f);
      }
    }
    TaskReporter reporter = startReporter(umbilical);

    boolean useNewApi = job.getUseNewMapper();
    initialize(job, getJobID(), reporter, useNewApi);

    // check if it is a cleanupJobTask
    if (jobCleanup) {
      runJobCleanupTask(umbilical, reporter);
      return;
    }
    if (jobSetup) {
      runJobSetupTask(umbilical, reporter);
      return;
    }
    if (taskCleanup) {
      runTaskCleanupTask(umbilical, reporter);
      return;
    }
    //sendSend(umbilical);
    if (useNewApi) {
      System.out.println("新事前:"+umbilical.getClass().getName());
      LOG.info("新事前:"+umbilical.getClass().getName());
      runNewMapper(job, splitMetaInfo, umbilical, reporter);
    } else {
      System.out.println("旧事前:"+umbilical.getClass().getName());
      LOG.info("旧事前:"+umbilical.getClass().getName());
      runOldMapper(job, splitMetaInfo, umbilical, reporter);
    }
    LOG.info("事后:"+umbilical.getClass().getName());
    System.out.println("事后:"+umbilical.getClass().getName());
    //sendSend(umbilical);
    done(umbilical, reporter);

  }

这部分是我加过log的run()方法,因为图省事,找日志找起来比较方便,就直接使用System.out.println()来做输出了。这样的话当运行完之后,所有的输出都会在hadoop目录下logs/userlogs/stdout里面。

可以看到run()方法主要有两个参数:

  • final JobConf job
    第一个参数主要是 Job的一些配置,可能会影响到maptask运行时候的一些方式。

  • final TaskUmbilicalProtocol umbilical
    这个参数就比较重要了,主要是的事件通信都是通过这个对象的。具体的在说MapTask所涉及到的状态机的时候再说吧。

这个类一部分都是一些初始化的工作,都很轻松就能看懂,主要是在

if (useNewApi) {
      System.out.println("新事前:"+umbilical.getClass().getName());
      LOG.info("新事前:"+umbilical.getClass().getName());
      runNewMapper(job, splitMetaInfo, umbilical, reporter);
    } else {
      System.out.println("旧事前:"+umbilical.getClass().getName());
      LOG.info("旧事前:"+umbilical.getClass().getName());
      runOldMapper(job, splitMetaInfo, umbilical, reporter);
    }
    LOG.info("事后:"+umbilical.getClass().getName());
    System.out.println("事后:"+umbilical.getClass().getName());
    //sendSend(umbilical);
    done(umbilical, reporter);

这一部分,判断用户是否指定使用新的map方式还是旧的map方式(新的方式和旧的方式主要功能并没有变化,主要是新的runNewMapper在架构上要比runOldMapper好一点。。。官方说的),这里我们以runOldMapper为例

InputSplit inputSplit = getSplitDetails(new Path(splitIndex.getSplitLocation()),
            splitIndex.getStartOffset());

这部分代码是指,map任务得到job分配给他的需要他来计算的那一部分分片。

RecordReader<INKEY, INVALUE> in = isSkipping() ?
            new SkippingRecordReader<INKEY, INVALUE>(umbilical, reporter, job) :
            new TrackedRecordReader<INKEY, INVALUE>(reporter, job);

这一部分是实例化一个RecordReader,主要用于按照行或者某种方式来读取自己需要计算的那一个分片。具体取决于这里被实例化的是哪一个实现类。
然后是hadoop会调用用户编写的map方法用来处理数据。

再下面是MapOutputCollector这个类,主要用于处理map的输出。

这里面有很多方法比较重要,比如sortAndSpill()这个方法。
这个方法主要是被SpillThread调用的,
SpillThread这个线程在MapOutputBuffer初始化时被启动,它会一直监视着环形缓冲区当环形缓冲区超过一定值(我记得源码里面好像是写了是在大部分情况下是百分之八十被占满后)的时候将会调用sortAndSpill方法,讲环形缓冲区中已经计算完毕的数据写到本地文件中。

当整个runOldMapper(或者是runNewMapper)完毕后将会执行done()函数发送事件,通过状态机变迁完成一些事情(这部分下次会提到)

大概主要的流程也就是这几个,如果有需要的或者不明白的地方,欢迎发邮件给我heshulin@imudges.com。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值