关于hadoop mapreduce的job cleanup阶段

近期发现部分MR作业在cleanup阶段出现长时间延迟问题,从几分钟延长至1-2小时。经调查发现,原因是集群资源紧张导致任务排队。本文详细分析了问题原因,并提出了优化建议。


        近段时间发现好多分析的mr作业延迟1个小时到2个小时,其实那个作业平时可能会只需要20分钟。分析作业状态发现延迟是在job的cleanup阶段。

       近段时间由于用户的增长及数据的持续飙升,集群作业越来越多,每个作业占用槽位也不断增长,导致集群槽位紧张,所以集群出现排队现象本来运算正常,但是如果整个作业setup、map、reduce都处理完了,仅剩cleanup(极其轻量)没执行完导致延迟1-2小时,这个太也能搞!

看下某个作业状态数据(注:这个作业很小,1-2分钟执行完毕):


可以看到setup\map\reduce 在12:36到12::37之间执行完毕,但是cleanup却在14:31分才启动,而执行也只用了8s!

也就是说为了这8s,该作业完成等待了将近2个小时!

看下JOBTRACKER日志:

12:39:06,580 INFO org.apache.hadoop.mapred.JobTracker: Adding task (JOB_CLEANUP) 'attempt_201212261519_3151096_m_000002_0' to tip task_201212261519_3151096_m
_000002, for tracker ...

说明mr执行完毕后即分配了task并提交到了tt.

在tt上查看日志搜索 该attampt.

 14:31:45,064 INFO org.apache.hadoop.mapred.TaskTracker: Trying to launch : attempt_201212261519_3151096_m_000002_0 which needs 1 slots


说明该task一直在tt上等待。下面看下相关代码:

在类org.apache.hadoop.mapred.TaskTracker 的run()方法里:

try {
              State osState = offerService();
              if (osState == State.STALE) {
                staleState = true;
              } else if (osState == State.DENIED) {
                denied = true;
              }
 } catch (Exception ex) {
    ...
 }
其中红色标出的为tt提供服务的主要方法,在该方法里有:

TaskTrackerAction[] actions = heartbeatResponse.getActions();
if (action instanceof LaunchTaskAction) {
              addToTaskQueue((LaunchTaskAction)action);
            } else if (action instanceof CommitTaskAction) {
...
}
通过心跳获取到jt的指令后即处理指令。对于LaunchTaskAction即新task加入taskqueue,代码如下:

private void addToTaskQueue(LaunchTaskAction action) {
    if (action.getTask().isMapTask()) {
      mapLauncher.addToTaskQueue(action);
    } else {
      reduceLauncher.addToTaskQueue(action);
    }
  }
如果是map的话加入mapLauncher,reduce加入reduceLauncher。而 一般的cleanup都会是map。

这里的mapLauncher和reduceLauncher是tt启动时初始化的2个线程:

    mapLauncher = new TaskLauncher(TaskType.MAP, maxMapSlots);
    reduceLauncher = new TaskLauncher(TaskType.REDUCE, maxReduceSlots);
    mapLauncher.start();
    reduceLauncher.start();

加入队列即加入一个链表里。这是线程定义时初始化链表

public TaskLauncher(TaskType taskType, int numSlots) {
      this.maxSlots = numSlots;
      this.numFreeSlots = new IntWritable(numSlots);
      this.tasksToLaunch = new LinkedList<TaskInProgress>();
      setDaemon(true);
      setName("TaskLauncher for " + taskType + " tasks");
    }
加入链表
public void addToTaskQueue(LaunchTaskAction action) {
      synchronized (tasksToLaunch) {
        TaskInProgress tip = registerTask(action, this);
        tasksToLaunch.add(tip);
        tasksToLaunch.notifyAll();
      }
    }
线程随TT启动,实时去查询链表,如果链表存在则取出第一个!

             //get the TIP
            tip = tasksToLaunch.remove(0);
            task = tip.getTask();
            LOG.info("Trying to launch : " + tip.getTask().getTaskID() + 
                     " which needs " + task.getNumSlotsRequired() + " slots");
通过比对日志,所有分配到tt的map作业确实也是根据先后顺序去处理的。但这导致了开头的问题!



优化方案:  建议cleanup与其他map或reduce区分开来,cleanup的优先级应高于其他map处理作业!


可能有些地方考虑欠妥,欢迎批评指正







评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值