optimize sort pods
Signed-off-by: dongjiang <dongjiang1989@126.com>
This commit is contained in:
parent
3fcef07664
commit
9b2267ca1c
|
|
@ -98,6 +98,7 @@ func evictPodsFromSourceNodes(sourceNodes, targetNodes []*NodeUtilization, tasks
|
|||
// victims select algorithm:
|
||||
// 1. Evict pods from nodes with high utilization to low utilization
|
||||
// 2. As to one node, evict pods from low priority to high priority. If the priority is same, evict pods according to QoS from low to high
|
||||
// 3. If the QoS is same, evict pods in order of creation time from latest to earliest.
|
||||
victims := make([]*api.TaskInfo, 0)
|
||||
for _, node := range sourceNodes {
|
||||
if len(node.pods) == 0 {
|
||||
|
|
@ -139,20 +140,27 @@ func getScoreForNode(index int, nodeUtilizationList []*NodeUtilization) float64
|
|||
// sortPods return the pods in order according the priority and QoS
|
||||
func sortPods(pods []*v1.Pod) {
|
||||
cmp := func(i, j int) bool {
|
||||
// sort by pod priority
|
||||
if pods[i].Spec.Priority == nil && pods[j].Spec.Priority != nil {
|
||||
return true
|
||||
}
|
||||
if pods[j].Spec.Priority == nil && pods[i].Spec.Priority != nil {
|
||||
return false
|
||||
}
|
||||
// sort by pod Qos
|
||||
if (pods[j].Spec.Priority == nil && pods[i].Spec.Priority == nil) || (*pods[i].Spec.Priority == *pods[j].Spec.Priority) {
|
||||
if v1qos.GetPodQOS(pods[i]) == v1.PodQOSBestEffort {
|
||||
return true
|
||||
if v1qos.GetPodQOS(pods[i]) != v1qos.GetPodQOS(pods[j]) {
|
||||
if v1qos.GetPodQOS(pods[i]) == v1.PodQOSBestEffort {
|
||||
return true
|
||||
}
|
||||
if v1qos.GetPodQOS(pods[i]) == v1.PodQOSBurstable && v1qos.GetPodQOS(pods[j]) == v1.PodQOSGuaranteed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
// sort by pod create time
|
||||
return pods[i].GetCreationTimestamp().Time.After(pods[j].GetCreationTimestamp().Time)
|
||||
}
|
||||
if v1qos.GetPodQOS(pods[i]) == v1.PodQOSBurstable && v1qos.GetPodQOS(pods[j]) == v1.PodQOSGuaranteed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return *pods[i].Spec.Priority < *pods[j].Spec.Priority
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
Copyright 2025 The Volcano Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rescheduling
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func TestSortPods(t *testing.T) {
|
||||
createTimeOld := time.Now()
|
||||
createTime := createTimeOld.Add(time.Second)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pods []*corev1.Pod
|
||||
wants []*corev1.Pod
|
||||
}{
|
||||
{
|
||||
name: "pods list empty",
|
||||
pods: []*corev1.Pod{},
|
||||
wants: []*corev1.Pod{},
|
||||
},
|
||||
{
|
||||
name: "pods sort by pod priority",
|
||||
pods: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(1)),
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(2)),
|
||||
},
|
||||
},
|
||||
},
|
||||
wants: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(1)),
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(2)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pods sort by pod priority nil",
|
||||
pods: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(1)),
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
wants: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Priority: ptr.To(int32(1)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pods sort by pod Qos",
|
||||
pods: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "C",
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
},
|
||||
wants: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "C",
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pods sort by pod CreatTime",
|
||||
pods: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "AA",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "BB",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "C",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "CC",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
},
|
||||
wants: []*corev1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "CC",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "C",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "BB",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "B",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("2500M"),
|
||||
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "AA",
|
||||
CreationTimestamp: metav1.Time{Time: createTime},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "A",
|
||||
CreationTimestamp: metav1.Time{Time: createTimeOld},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: resource.MustParse("250M"),
|
||||
corev1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sortPods(tt.pods)
|
||||
assert.Equal(t, tt.wants, tt.pods, "sortPods")
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue