Skip to content

Commit 4bf5b4c

Browse files
committed
YARN-6538. Inter Queue preemption is not happening when DRF is configured in extreme resource scale cases.
1 parent 0ef572a commit 4bf5b4c

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DefaultResourceCalculator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ public boolean isAnyMajorResourceZeroOrNegative(Resource resource) {
153153
return resource.getMemorySize() <= 0;
154154
}
155155

156+
@Override
157+
public boolean isAnyRequestedResourceZeroOrNegative(Resource available, Resource resource) {
158+
return resource.getMemorySize() == 0;
159+
}
156160
@Override
157161
public boolean isAnyMajorResourceAboveZero(Resource resource) {
158162
return resource.getMemorySize() > 0;

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DominantResourceCalculator.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,22 @@ public boolean isAnyMajorResourceZeroOrNegative(Resource resource) {
642642
return false;
643643
}
644644

645+
@Override
646+
public boolean isAnyRequestedResourceZeroOrNegative(Resource available, Resource resource) {
647+
int maxLength = ResourceUtils.getNumberOfCountableResourceTypes();
648+
for (int i = 0; i < maxLength; i++) {
649+
ResourceInformation resourceInformation = available.getResourceInformation(
650+
i);
651+
if (resourceInformation.getValue() != 0L) {
652+
ResourceInformation ri2 = resource.getResourceInformation(i);
653+
if (ri2.getValue() <= 0L) {
654+
return true;
655+
}
656+
}
657+
}
658+
return false;
659+
}
660+
645661
@Override
646662
public boolean isAnyMajorResourceAboveZero(Resource resource) {
647663
int maxLength = ResourceUtils.getNumberOfCountableResourceTypes();

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceCalculator.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ public abstract float divide(
278278
*/
279279
public abstract boolean isAnyMajorResourceZeroOrNegative(Resource resource);
280280

281+
/**
282+
* Check if resource has any available (those that have non-zero available value)
283+
* major resource types (which are all NodeManagers included) a zero value or negative value.
284+
*
285+
* @param available available resource
286+
* @param resource resource
287+
* @return returns true if any resource is zero.
288+
*/
289+
public abstract boolean isAnyRequestedResourceZeroOrNegative(Resource available, Resource resource);
290+
281291
/**
282292
* Get resource <code>r</code>and normalize down using step-factor
283293
* <code>stepFactor</code>.

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/monitor/capacity/AbstractPreemptableResourceCalculator.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,11 @@ protected void computeFixpointAllocation(Resource totGuarant,
224224

225225
for (Iterator<TempQueuePerPartition> i = underserved.iterator(); i
226226
.hasNext();) {
227-
if (!rc.isAnyMajorResourceAboveZero(unassigned)) {
227+
// Exit the loop once any of the unassigned resources reach zero, except the optional
228+
// ones which the queue has no guarantee on. This should ensure that extreme cases
229+
// where one of the resources are significantly larger than the other (i.e: way below 1
230+
// vcore per GB of memory)
231+
if (rc.isAnyRequestedResourceZeroOrNegative(totGuarant, unassigned)) {
228232
break;
229233
}
230234

@@ -266,7 +270,6 @@ protected void computeFixpointAllocation(Resource totGuarant,
266270
}
267271
}
268272

269-
270273
/**
271274
* This method is visible to allow sub-classes to override the initialization
272275
* behavior.

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/monitor/capacity/TestProportionalCapacityPreemptionPolicyInterQueueWithDRF.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.LeafQueue;
3232
import org.apache.hadoop.yarn.util.resource.DominantResourceCalculator;
3333
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
34+
import org.mockito.Matchers;
3435

3536
import static org.mockito.ArgumentMatchers.any;
3637
import static org.mockito.ArgumentMatchers.argThat;
@@ -89,6 +90,56 @@ public void testInterQueuePreemptionWithMultipleResource() throws Exception {
8990
getAppAttemptId(2))));
9091
}
9192

93+
@Test
94+
public void testInterQueuePreemptionWithMultipleResourceUnbalancedCase() throws IOException {
95+
/**
96+
* Queue structure is:
97+
*
98+
* <pre>
99+
* root
100+
* / \
101+
* a b
102+
* </pre>
103+
*
104+
* Scenario: Queue B : Queue A has 90/10% capacity share.
105+
* Almost all the resources are allocated to Queue A, but based on memory alone
106+
* containers still can be allocated elsewhere. The app on A requests a lot more.
107+
* The app on Queue B needs a little memory (still fits in the remaining resources),
108+
* but needs a lot of vcores. Enough resources must be preempted from the app on A
109+
* to allow the app on B launch.
110+
*/
111+
String labelsConfig = "=65536:50,true;"; // default partition
112+
String nodesConfig = // only one node
113+
"n1=";
114+
115+
String queuesConfig =
116+
// guaranteed, max, used, pending
117+
"root(=[65536:50 65536:50 61440:45 132096:525]);" + // root
118+
"-a(=[2048:5 65536:50 61440:45 131072:500]);" + // a
119+
"-b(=[63488:45 65536:50 0:0 1024:25]);"; // b
120+
121+
122+
String appsConfig =
123+
//queueName\t(priority,resource,host,expression,#repeat,reserved)
124+
"a\t(1,61440:45,n1,,20,false);" + // app1 in a
125+
"b\t(1,1024:25,n1,,30,false)"; // app2 in b
126+
127+
buildEnv(labelsConfig, nodesConfig, queuesConfig, appsConfig, true);
128+
Resource ul = Resource.newInstance(65536, 50);
129+
when(((LeafQueue)(cs.getQueue("root.a")))
130+
.getResourceLimitForAllUsers(any(), any(), any(), any())
131+
).thenReturn(ul);
132+
policy.editSchedule();
133+
134+
// Preemption should happen in Queue a, preempt to Queue b
135+
verify(eventHandler, times(1)).handle(Matchers.argThat(
136+
new TestProportionalCapacityPreemptionPolicy.IsPreemptionRequestFor(
137+
getAppAttemptId(1))));
138+
verify(eventHandler, never()).handle(Matchers.argThat(
139+
new TestProportionalCapacityPreemptionPolicy.IsPreemptionRequestFor(
140+
getAppAttemptId(2))));
141+
}
142+
92143
@Test
93144
public void testInterQueuePreemptionWithNaturalTerminationFactor()
94145
throws Exception {

0 commit comments

Comments
 (0)