diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestAMRMClient.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestAMRMClient.java index 1b2bca32d25..43b394e05de 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestAMRMClient.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestAMRMClient.java @@ -252,6 +252,61 @@ public void testAMRMClientNoMatchingRequests() } @Test (timeout=60000) + public void testAMRMClientRacksRelaxLocality() throws YarnException, IOException { + AMRMClientImpl amClient = null; + try { + // start am rm client + amClient = (AMRMClientImpl) AMRMClient.createAMRMClient(); + + amClient.init(conf); + amClient.start(); + + amClient.registerApplicationMaster("Host", 10000, ""); + + // setup container request + boolean relaxLocality = false; + amClient.addContainerRequest( + new ContainerRequest(capability, null, racks, priority, relaxLocality)); + + int containersRequestedAny = 1; + + int allocatedContainerCount = 0; + Set releases = new TreeSet(); + + while (allocatedContainerCount < containersRequestedAny) { + AllocateResponse allocResponse = amClient.allocate(0.1f); + assertEquals(0, amClient.ask.size()); + assertEquals(0, amClient.release.size()); + + assertEquals(nodeCount, amClient.getClusterNodeCount()); + allocatedContainerCount += allocResponse.getAllocatedContainers().size(); + for(Container container : allocResponse.getAllocatedContainers()) { + ContainerId rejectContainerId = container.getId(); + releases.add(rejectContainerId); + amClient.releaseAssignedContainer(rejectContainerId); + } + + if(allocatedContainerCount < containersRequestedAny) { + // let NM heartbeat to RM and trigger allocations + triggerSchedulingWithNMHeartBeat(); + } + } + + assertEquals(allocatedContainerCount, containersRequestedAny); + assertEquals(1, releases.size()); + assertEquals(0, amClient.ask.size()); + + amClient.unregisterApplicationMaster(FinalApplicationStatus.SUCCEEDED, + null, null); + + } finally { + if (amClient != null && amClient.getServiceState() == STATE.STARTED) { + amClient.stop(); + } + } + } + + @Test (timeout=60000) public void testAMRMClientMatchingFit() throws YarnException, IOException { AMRMClient amClient = null; try { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/allocator/RegularContainerAllocator.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/allocator/RegularContainerAllocator.java index f753d31fdbf..210bcd5d3c4 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/allocator/RegularContainerAllocator.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/allocator/RegularContainerAllocator.java @@ -367,7 +367,8 @@ private ContainerAllocation assignRackLocalContainers( FiCaSchedulerNode node, SchedulerRequestKey schedulerKey, RMContainer reservedContainer, SchedulingMode schedulingMode, ResourceLimits currentResoureLimits) { - if (canAssign(schedulerKey, node, NodeType.RACK_LOCAL, reservedContainer)) { + if (canAssign(schedulerKey, node, NodeType.RACK_LOCAL, + reservedContainer)) { return assignContainer(clusterResource, node, schedulerKey, rackLocalAsk, NodeType.RACK_LOCAL, reservedContainer, schedulingMode, currentResoureLimits); @@ -427,6 +428,11 @@ private ContainerAllocation assignContainersOnNode(Resource clusterResource, // Rack-local PendingAsk rackLocalAsk = application.getPendingAsk(schedulerKey, node.getRackName()); + PendingAsk offSwitchAsk = + application.getPendingAsk(schedulerKey, ResourceRequest.ANY); + int offSwitchAskCount = offSwitchAsk.getCount(); + boolean offSwitchCanDelayTo = appInfo.canDelayTo(schedulerKey, + ResourceRequest.ANY); if (rackLocalAsk.getCount() > 0) { if (!appInfo.canDelayTo(schedulerKey, node.getRackName())) { ActivitiesLogger.APP.recordSkippedAppActivityWithoutAllocation( @@ -438,23 +444,21 @@ private ContainerAllocation assignContainersOnNode(Resource clusterResource, requestLocalityType = requestLocalityType == null ? NodeType.RACK_LOCAL : requestLocalityType; - allocation = assignRackLocalContainers(clusterResource, rackLocalAsk, node, schedulerKey, reservedContainer, schedulingMode, currentResoureLimits); if (Resources.greaterThan(rc, clusterResource, - allocation.getResourceToBeAllocated(), Resources.none())) { + allocation.getResourceToBeAllocated(), Resources.none()) || + ((offSwitchAskCount > 0) && !offSwitchCanDelayTo)) { allocation.requestLocalityType = requestLocalityType; return allocation; } } // Off-switch - PendingAsk offSwitchAsk = - application.getPendingAsk(schedulerKey, ResourceRequest.ANY); - if (offSwitchAsk.getCount() > 0) { - if (!appInfo.canDelayTo(schedulerKey, ResourceRequest.ANY)) { + if (offSwitchAskCount > 0) { + if (!offSwitchCanDelayTo) { ActivitiesLogger.APP.recordSkippedAppActivityWithoutAllocation( activitiesManager, node, application, priority, ActivityDiagnosticConstant.SKIP_PRIORITY_BECAUSE_OF_RELAX_LOCALITY); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/capacity-scheduler.xml hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/capacity-scheduler.xml index 80a9fec72c4..d0c81ded4e0 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/capacity-scheduler.xml +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/resources/capacity-scheduler.xml @@ -99,12 +99,12 @@ yarn.scheduler.capacity.node-locality-delay - -1 + 40 - Number of missed scheduling opportunities after which the CapacityScheduler - attempts to schedule rack-local containers. - Typically this should be set to number of racks in the cluster, this - feature is disabled by default, set to -1. + Number of missed scheduling opportunities after which the CapacityScheduler + attempts to schedule rack-local containers. + When setting this parameter, the size of the cluster should be taken into account. + We use 40 as the default value, which is approximately the number of nodes in one rack.