关于hadoop mapreduce的job cleanup阶段

来源:互联网 发布:怎么提高淘宝销售量 编辑:程序博客网 时间:2024/04/27 23:36


        近段时间发现好多分析的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处理作业!


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







原创粉丝点击