This is an automated email from the ASF dual-hosted git repository.
wilfreds pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-core.git
The following commit(s) were added to refs/heads/master by this push:
new eb037271 [YUNIKORN-1936] Auto scaling to check user quota (#640)
eb037271 is described below
commit eb037271a37d9bbf2c8a829b4a37c20f527d08a7
Author: qzhu <[email protected]>
AuthorDate: Tue Oct 31 15:45:52 2023 +1100
[YUNIKORN-1936] Auto scaling to check user quota (#640)
With the introduction of user quotas node auto scaling logic should also
check the user quota and not just the queue quota. User quotas should
prevent upscaling requests similar to queue quotas.
Overall logic remains, the distribution could change if users are limited
by their own quotas.
Closes: #640
Signed-off-by: Wilfred Spiegelenburg <[email protected]>
---
pkg/scheduler/objects/application.go | 6 +--
pkg/scheduler/objects/application_test.go | 63 +++++++++++++++++++++++++++++++
pkg/scheduler/objects/queue.go | 4 +-
3 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/pkg/scheduler/objects/application.go
b/pkg/scheduler/objects/application.go
index 733416cc..d301790b 100644
--- a/pkg/scheduler/objects/application.go
+++ b/pkg/scheduler/objects/application.go
@@ -909,22 +909,22 @@ func (sa *Application) canAskReserve(ask *AllocationAsk)
bool {
return pending > len(resNumber)
}
-func (sa *Application) getOutstandingRequests(headRoom *resources.Resource,
total *[]*AllocationAsk) {
+func (sa *Application) getOutstandingRequests(headRoom *resources.Resource,
userHeadRoom *resources.Resource, total *[]*AllocationAsk) {
sa.RLock()
defer sa.RUnlock()
if sa.sortedRequests == nil {
return
}
-
for _, request := range sa.sortedRequests {
if request.GetPendingAskRepeat() == 0 {
continue
}
// ignore nil checks resource function calls are nil safe
- if headRoom.FitInMaxUndef(request.GetAllocatedResource()) {
+ if headRoom.FitInMaxUndef(request.GetAllocatedResource()) &&
userHeadRoom.FitInMaxUndef(request.GetAllocatedResource()) {
// if headroom is still enough for the resources
*total = append(*total, request)
headRoom.SubOnlyExisting(request.GetAllocatedResource())
+
userHeadRoom.SubOnlyExisting(request.GetAllocatedResource())
}
}
}
diff --git a/pkg/scheduler/objects/application_test.go
b/pkg/scheduler/objects/application_test.go
index cda3de42..0edb57ec 100644
--- a/pkg/scheduler/objects/application_test.go
+++ b/pkg/scheduler/objects/application_test.go
@@ -2281,6 +2281,69 @@ func TestAppDoesNotFitEvent(t *testing.T) {
assert.Equal(t, "alloc-0", records[1].ObjectID)
}
+func TestGetOutstandingRequests(t *testing.T) {
+ // Create a sample Resource and AllocationAsk
+ resMap := map[string]string{"memory": "100", "vcores": "10"}
+ res, err := resources.NewResourceFromConf(resMap)
+ assert.NilError(t, err, "failed to create resource with error")
+
+ allocationAsk1 := newAllocationAsk("alloc-1", "app-1", res)
+ allocationAsk2 := newAllocationAsk("alloc-2", "app-1", res)
+
+ // Create an Application instance
+ app := &Application{
+ ApplicationID: "app-1",
+ queuePath: "default",
+ }
+
+ app.user = security.UserGroup{
+ User: "user1",
+ Groups: []string{"group1"},
+ }
+
+ // Set up the Application's sortedRequests with AllocationAsks
+ sr := sortedRequests{}
+ sr.insert(allocationAsk1)
+ sr.insert(allocationAsk2)
+ app.sortedRequests = sr
+
+ // Test Case 1: queueHeadroom meets, but userHeadroom does not
+ queueHeadroom, err :=
resources.NewResourceFromConf(map[string]string{"memory": "250", "vcores":
"25"})
+ assert.NilError(t, err, "failed to create queue headroom resource with
error")
+ userHeadroom, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "5"})
+ assert.NilError(t, err, "failed to create user headroom resource with
error")
+ total1 := []*AllocationAsk{}
+ app.getOutstandingRequests(queueHeadroom, userHeadroom, &total1)
+ assert.Equal(t, 0, len(total1), "expected one outstanding request for
TestCase 1")
+
+ // Test Case 2: Both queueHeadroom and userHeadroom meet
+ queueHeadroom2, err :=
resources.NewResourceFromConf(map[string]string{"memory": "250", "vcores":
"25"})
+ assert.NilError(t, err, "failed to create queue headroom resource with
error")
+ userHeadroom2, err :=
resources.NewResourceFromConf(map[string]string{"memory": "250", "vcores":
"25"})
+ assert.NilError(t, err, "failed to create user headroom resource with
error")
+ total2 := []*AllocationAsk{}
+ app.getOutstandingRequests(queueHeadroom2, userHeadroom2, &total2)
+ assert.Equal(t, 2, len(total2), "expected two outstanding requests for
TestCase 2")
+
+ // Test Case 3: queueHeadroom does not meet, but userHeadroom meets
+ queueHeadroom3, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "5"})
+ assert.NilError(t, err, "failed to create queue headroom resource with
error")
+ userHeadroom3, err :=
resources.NewResourceFromConf(map[string]string{"memory": "250", "vcores":
"25"})
+ assert.NilError(t, err, "failed to create user headroom resource with
error")
+ total3 := []*AllocationAsk{}
+ app.getOutstandingRequests(queueHeadroom3, userHeadroom3, &total3)
+ assert.Equal(t, 0, len(total3), "expected one outstanding request for
TestCase 3")
+
+ // Test Case 4: Neither queueHeadroom nor userHeadroom meets
+ queueHeadroom4, err :=
resources.NewResourceFromConf(map[string]string{"memory": "50", "vcores": "5"})
+ assert.NilError(t, err, "failed to create queue headroom resource with
error")
+ userHeadroom4, err :=
resources.NewResourceFromConf(map[string]string{"memory": "80", "vcores": "8"})
+ assert.NilError(t, err, "failed to create user headroom resource with
error")
+ total4 := []*AllocationAsk{}
+ app.getOutstandingRequests(queueHeadroom4, userHeadroom4, &total4)
+ assert.Equal(t, 0, len(total4), "expected no outstanding requests for
TestCase 4")
+}
+
func (sa *Application) addPlaceholderDataWithLocking(ask *AllocationAsk) {
sa.Lock()
defer sa.Unlock()
diff --git a/pkg/scheduler/objects/queue.go b/pkg/scheduler/objects/queue.go
index 985ff024..f82b7899 100644
--- a/pkg/scheduler/objects/queue.go
+++ b/pkg/scheduler/objects/queue.go
@@ -1375,7 +1375,9 @@ func (sq *Queue) GetQueueOutstandingRequests(total
*[]*AllocationAsk) {
// we calculate all the requests that can fit into the queue's
headroom,
// all these requests are qualified to trigger the up scaling.
for _, app := range sq.sortApplications(false, false) {
- app.getOutstandingRequests(headRoom, total)
+ // calculate the users' headroom
+ userHeadroom :=
ugm.GetUserManager().Headroom(app.queuePath, app.ApplicationID, app.user)
+ app.getOutstandingRequests(headRoom, userHeadroom,
total)
}
} else {
for _, child := range sq.sortQueues() {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]