Capacity Scheduler Node Label在queue mapping情况下引起的提交stuck

为一个大客户启用Node Label功能,发现启用后,使用用户提交任务后,appmaster无法启动,导致了整个任务无法启动,集群无法提交任务。
集群的版本是Hadoop 2.7.2,Node Label 把整个集群分为两部分,一部分label为core,一部分label为vvp。在客户端提交任务的时候可以指定队列,这种情况下队列信息是在提交的context里面设置,而对于不显示的指定队列的应用,设置的是默认队列,即default,这段代码可以参考YARN Runner的实现。

appContext.setApplicationId(applicationId);                // ApplicationId
appContext.setQueue(                                       // Queue name
    jobConf.get(JobContext.QUEUE_NAME,
    YarnConfiguration.DEFAULT_QUEUE_NAME));

ResourceManager通过RMClientService接收到提交的请求后,会放置的状态机中,通过多次的异步处理,会生成RMAppAttempt对象,并生成AppMaster的request,相关代码在RMAppManager类中。
方法是validateAndCreateResourceRequest,在这里面提交的appmaster依然使用的是default队列,并没有通过queue mapping获取到他的实际映射队列,导致了无法获取label信息,从而无法调度。

    SchedulerUtils.normalizeAndValidateRequest(amReq,
        scheduler.getMaximumResourceCapability(),
        submissionContext.getQueue(), scheduler, isRecovery, rmContext);

在这段代码中,submissionContext的Queue依然是default,获取的是default对应的label,通常是默认的partition,而如果用户和组映射到了其他的Queue,而这个Queue需要到特定的Label运行,就会导致错误。
解决方法:

    String queueName = submissionContext.getQueue();
    if(scheduler instanceof CapacityScheduler) {
      queueName = ((CapacityScheduler)scheduler).getQueueMappings(queueName, user);
    }
    SchedulerUtils.normalizeAndValidateRequest(amReq,
        scheduler.getMaximumResourceCapability(),
        queueName, scheduler, isRecovery, rmContext);

在Capacity Scheduler中暴露出queue mapping的方法去获取mapping的queue,从而获取到实际的Label。

在Hadoop 2.8.5中这个问题已经被fix了,fix的方法如下:

  if (rmContext.getQueuePlacementManager() != null) {
    // We only do queue mapping when it's a new application
    rmContext.getQueuePlacementManager().placeApplication(
        submissionContext, user);
  }

在生成amReq之前,先根据QueueMapping重新设置queue的Name,从而获取到映射后的Queue,拿到最后的Label。
由于2.8.5这个改动远远大于2.7.3的改动,所以这次采用自己的fix方案解决这一问题。

Print Friendly

jiang yu

Leave a Reply