diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java index 96d309c547e..9d2b2868041 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java @@ -213,9 +213,11 @@ protected void setupQueueConfigs(Resource clusterResource, (int) (maxSystemApps * queueCapacities.getAbsoluteCapacity()); } } - maxApplicationsPerUser = Math.min(maxApplications, + maxApplicationsPerUser = getUserLimitFactor() != -1 + ? Math.min(maxApplications, (int) (maxApplications * (usersManager.getUserLimit() / 100.0f) - * usersManager.getUserLimitFactor())); + * usersManager.getUserLimitFactor())) + : maxApplications; maxAMResourcePerQueuePercent = conf.getMaximumApplicationMasterResourcePerQueuePercent( @@ -712,21 +714,33 @@ public Resource getUserAMResourceLimitPerPartition( Resource queuePartitionResource = getEffectiveCapacity(nodePartition); - Resource userAMLimit = Resources.multiplyAndNormalizeUp( + Resource userAMLimit = getUserLimitFactor() != -1 + ? Resources.multiplyAndNormalizeUp( resourceCalculator, queuePartitionResource, queueCapacities.getMaxAMResourcePercentage(nodePartition) * effectiveUserLimit * usersManager.getUserLimitFactor(), - minimumAllocation); + minimumAllocation) + : Resources.multiplyAndNormalizeUp( + resourceCalculator, queuePartitionResource, + queueCapacities.getMaxAMResourcePercentage(nodePartition), + minimumAllocation); + userAMLimit = Resources.min(resourceCalculator, lastClusterResource, userAMLimit, Resources.clone(getAMResourceLimitPerPartition(nodePartition))); - Resource preWeighteduserAMLimit = Resources.multiplyAndNormalizeUp( + Resource preWeighteduserAMLimit = getUserLimitFactor() != -1 + ? Resources.multiplyAndNormalizeUp( resourceCalculator, queuePartitionResource, queueCapacities.getMaxAMResourcePercentage(nodePartition) * preWeightedUserLimit * usersManager.getUserLimitFactor(), - minimumAllocation); + minimumAllocation) + : Resources.multiplyAndNormalizeUp( + resourceCalculator, queuePartitionResource, + queueCapacities.getMaxAMResourcePercentage(nodePartition), + minimumAllocation); + preWeighteduserAMLimit = Resources.min(resourceCalculator, lastClusterResource, preWeighteduserAMLimit, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/ParentQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/ParentQueue.java index 7d82faeeef4..548296460b0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/ParentQueue.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/ParentQueue.java @@ -1177,10 +1177,13 @@ private void deriveCapacityFromAbsoluteConfigurations(String label, } leafQueue.setMaxApplications(maxApplications); - int maxApplicationsPerUser = Math.min(maxApplications, + int maxApplicationsPerUser = + leafQueue.getUsersManager().getUserLimitFactor() != -1 + ? Math.min(maxApplications, (int) (maxApplications * (leafQueue.getUsersManager().getUserLimit() / 100.0f) - * leafQueue.getUsersManager().getUserLimitFactor())); + * leafQueue.getUsersManager().getUserLimitFactor())) + : maxApplications; leafQueue.setMaxApplicationsPerUser(maxApplicationsPerUser); LOG.info("LeafQueue:" + leafQueue.getQueuePath() + ", maxApplications=" + maxApplications + ", maxApplicationsPerUser=" diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/UsersManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/UsersManager.java index 14766e9953d..90a23d3d6a1 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/UsersManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/UsersManager.java @@ -791,8 +791,15 @@ private Resource computeUserLimit(String userName, Resource clusterResource, // IGNORE_PARTITION_EXCLUSIVITY allocation. Resource maxUserLimit = Resources.none(); if (schedulingMode == SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY) { - maxUserLimit = Resources.multiplyAndRoundDown(queueCapacity, - getUserLimitFactor()); + // If user-limit-factor set to -1, we should disabled user limit. + if (getUserLimitFactor() != -1) { + maxUserLimit = Resources.multiplyAndRoundDown(queueCapacity, + getUserLimitFactor()); + } else { + maxUserLimit = lQueue. + getEffectiveMaxCapacityDown(nodePartition, lQueue.getMinimumAllocation()); + } + } else if (schedulingMode == SchedulingMode.IGNORE_PARTITION_EXCLUSIVITY) { maxUserLimit = partitionResource; } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestLeafQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestLeafQueue.java index e7abf7d53df..7eff1ce16b7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestLeafQueue.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestLeafQueue.java @@ -1436,6 +1436,143 @@ public void testUserLimitCacheActiveUsersChanged() throws Exception { .get(SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY).getMemorySize()); } + @Test + public void testDisabledUserLimitFactor() throws Exception { + // Mock the queue + LeafQueue a = stubLeafQueue((LeafQueue)queues.get(A)); + //unset maxCapacity + a.setMaxCapacity(1.0f); + // 4G memory + a.setCapacity(0.25f); + + when(csContext.getClusterResource()) + .thenReturn(Resources.createResource(16 * GB, 32)); + + // Users + final String user0 = "user0"; + final String user1 = "user1"; + + // Submit applications + final ApplicationAttemptId appAttemptId0 = + TestUtils.getMockApplicationAttemptId(0, 0); + FiCaSchedulerApp app0 = + new FiCaSchedulerApp(appAttemptId0, user0, a, + a.getAbstractUsersManager(), spyRMContext); + a.submitApplicationAttempt(app0, user0); + + final ApplicationAttemptId appAttemptId1 = + TestUtils.getMockApplicationAttemptId(1, 0); + FiCaSchedulerApp app1 = + new FiCaSchedulerApp(appAttemptId1, user1, a, + a.getAbstractUsersManager(), spyRMContext); + a.submitApplicationAttempt(app1, user1); // different user + + // Setup some nodes + String host0 = "127.0.0.1"; + FiCaSchedulerNode node0 = + TestUtils.getMockNode(host0, DEFAULT_RACK, 0, 8*GB); + String host1 = "127.0.0.2"; + FiCaSchedulerNode node1 = + TestUtils.getMockNode(host1, DEFAULT_RACK, 0, 8*GB); + + final int numNodes = 2; + Resource clusterResource = + Resources.createResource(numNodes * (8*GB), numNodes * 16); + when(csContext.getNumClusterNodes()).thenReturn(numNodes); + root.updateClusterResource(clusterResource, + new ResourceLimits(clusterResource)); + + // Setup resource-requests + Priority priority = TestUtils.createMockPriority(1); + app0.updateResourceRequests(Collections.singletonList( + TestUtils.createResourceRequest(ResourceRequest.ANY, 3*GB, 2, true, + priority, recordFactory))); + + app1.updateResourceRequests(Collections.singletonList( + TestUtils.createResourceRequest(ResourceRequest.ANY, 1*GB, 2, true, + priority, recordFactory))); + + Map apps = ImmutableMap.of( + app0.getApplicationAttemptId(), app0, app1.getApplicationAttemptId(), + app1); + Map nodes = ImmutableMap.of(node0.getNodeID(), + node0, node1.getNodeID(), node1); + + /** + * Start testing ... + */ + + // Set user-limit to 100 + // 4G memory min user limit if needed + a.setUserLimit(100); + + // Set user limit factor 1 + // Max use limit to 4G + a.setUserLimitFactor(1); + + root.updateClusterResource(clusterResource, + new ResourceLimits(clusterResource)); + + // There're two active users + assertEquals(2, a.getAbstractUsersManager().getNumActiveUsers()); + + // 1 container to user0 + applyCSAssignment(clusterResource, + a.assignContainers(clusterResource, node0, + new ResourceLimits(clusterResource), + SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps); + assertEquals(3*GB, a.getUsedResources().getMemorySize()); + assertEquals(3*GB, app0.getCurrentConsumption().getMemorySize()); + assertEquals(0*GB, app1.getCurrentConsumption().getMemorySize()); + + // Allocate one container to app1. Even if app0 + // submit earlier, it cannot get this container assigned since user0 + // will exceeded max user-limit 4G. + applyCSAssignment(clusterResource, + a.assignContainers(clusterResource, node0, + new ResourceLimits(clusterResource), + SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps); + assertEquals(4*GB, a.getUsedResources().getMemorySize()); + assertEquals(3*GB, app0.getCurrentConsumption().getMemorySize()); + assertEquals(1*GB, app1.getCurrentConsumption().getMemorySize()); + + // Allocate no containers to app0, because it's + // user-limit = 4G. app0's need 3+3 > 4G + applyCSAssignment(clusterResource, + a.assignContainers(clusterResource, node1, + new ResourceLimits(clusterResource), + SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps); + assertEquals(5*GB, a.getUsedResources().getMemorySize()); + assertEquals(3*GB, app0.getCurrentConsumption().getMemorySize()); + assertEquals(2*GB, app1.getCurrentConsumption().getMemorySize()); + + // app1 doesn't have outstanding resources, there's only one active user. + assertEquals("There should only be 1 active user!", + 1, a.getAbstractUsersManager().getNumActiveUsers()); + + // Set user limit factor to -1 + // Max use limit will not exist + a.setUserLimitFactor(-1); + + // Update now + root.updateClusterResource(clusterResource, + new ResourceLimits(clusterResource)); + + applyCSAssignment(clusterResource, + a.assignContainers(clusterResource, node1, + new ResourceLimits(clusterResource), + SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps); + + // Now app0 can get all 6G + assertEquals(8*GB, a.getUsedResources().getMemorySize()); + assertEquals(6*GB, app0.getCurrentConsumption().getMemorySize()); + + // app0 doesn't have outstanding resources, there will be no active users. + assertEquals("There should be no active users!", + 0, a.getAbstractUsersManager().getNumActiveUsers()); + + } + @Test public void testUserLimits() throws Exception { // Mock the queue