Skip to content

Commit 842aef3

Browse files
committed
adjust the Priority of General and Accurate Estimator of Karmada Scheduler
Signed-off-by: chaosi-zju <[email protected]>
1 parent d17faec commit 842aef3

File tree

6 files changed

+96
-9
lines changed

6 files changed

+96
-9
lines changed

pkg/descheduler/core/helper.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"encoding/json"
2222
"fmt"
2323
"math"
24+
"sort"
2425
"time"
2526

2627
"github.com/kr/pretty"
@@ -62,24 +63,39 @@ func NewSchedulingResultHelper(binding *workv1alpha2.ResourceBinding) *Schedulin
6263
func (h *SchedulingResultHelper) FillUnschedulableReplicas(unschedulableThreshold time.Duration) {
6364
reference := &h.Spec.Resource
6465
undesiredClusters, undesiredClusterNames := h.GetUndesiredClusters()
66+
6567
// Set the boundary.
6668
for i := range undesiredClusters {
6769
undesiredClusters[i].Unschedulable = math.MaxInt32
6870
}
69-
// Get the minimum value of MaxAvailableReplicas in terms of all estimators.
71+
72+
// get estimators and sort it by priority.
7073
estimators := estimatorclient.GetUnschedulableReplicaEstimators()
74+
sort.Slice(estimators, func(i, j int) bool {
75+
return estimators[i].GetPriority() > estimators[j].GetPriority()
76+
})
77+
78+
priorityOfAvailableEstimator := estimatorclient.EstimatorPriority(math.MinInt32)
7179
ctx := context.WithValue(context.TODO(), util.ContextKeyObject,
7280
fmt.Sprintf("kind=%s, name=%s/%s", reference.Kind, reference.Namespace, reference.Name))
81+
7382
for _, estimator := range estimators {
83+
// if higher-priority estimators have formed a full result of member clusters, no longer to call lower-priority estimator.
84+
if estimator.GetPriority() < priorityOfAvailableEstimator && clustersFullyEstimated(undesiredClusters) {
85+
break
86+
}
7487
res, err := estimator.GetUnschedulableReplicas(ctx, undesiredClusterNames, reference, unschedulableThreshold)
7588
if err != nil {
7689
klog.Errorf("Max cluster unschedulable replicas error: %v", err)
7790
continue
7891
}
92+
priorityOfAvailableEstimator = estimator.GetPriority()
7993
for i := range res {
94+
// if an estimator can only give a part of result of member clusters, same priority estimator will be called.
8095
if res[i].Replicas == estimatorclient.UnauthenticReplica {
8196
continue
8297
}
98+
// if two estimators are of the same priority, call both and choose the minimum value of each estimated result.
8399
if undesiredClusters[i].ClusterName == res[i].Name && undesiredClusters[i].Unschedulable > res[i].Replicas {
84100
undesiredClusters[i].Unschedulable = res[i].Replicas
85101
}
@@ -95,6 +111,16 @@ func (h *SchedulingResultHelper) FillUnschedulableReplicas(unschedulableThreshol
95111
klog.V(4).Infof("Target undesired cluster of unschedulable replica result: %s", pretty.Sprint(undesiredClusters))
96112
}
97113

114+
// clustersFullyEstimated whether estimators has gaven a full result of member clusters
115+
func clustersFullyEstimated(undesiredClusters []*TargetClusterWrapper) bool {
116+
for i := range undesiredClusters {
117+
if undesiredClusters[i].Unschedulable == math.MaxInt32 {
118+
return false
119+
}
120+
}
121+
return true
122+
}
123+
98124
// GetUndesiredClusters returns the cluster which of ready replicas are not reach the ready ones.
99125
func (h *SchedulingResultHelper) GetUndesiredClusters() ([]*TargetClusterWrapper, []string) {
100126
var clusters []*TargetClusterWrapper

pkg/descheduler/descheduler_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ func TestDescheduler_worker(t *testing.T) {
487487
}
488488
schedulerEstimator := estimatorclient.NewSchedulerEstimator(desched.schedulerEstimatorCache, 5*time.Second)
489489
estimatorclient.RegisterSchedulerEstimator(schedulerEstimator)
490+
defer estimatorclient.UnRegisterSchedulerEstimator(schedulerEstimator)
490491

491492
for _, c := range tt.args.unschedulable {
492493
cluster := c

pkg/estimator/client/accurate.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,24 @@ import (
3232

3333
// RegisterSchedulerEstimator will register a SchedulerEstimator.
3434
func RegisterSchedulerEstimator(se *SchedulerEstimator) {
35-
replicaEstimators["scheduler-estimator"] = se
36-
unschedulableReplicaEstimators["scheduler-estimator"] = se
35+
replicaEstimators = append(replicaEstimators, se)
36+
unschedulableReplicaEstimators = append(unschedulableReplicaEstimators, se)
37+
}
38+
39+
// UnRegisterSchedulerEstimator will unregister a SchedulerEstimator.
40+
func UnRegisterSchedulerEstimator(se *SchedulerEstimator) {
41+
for i := 0; i < len(replicaEstimators); i++ {
42+
if replicaEstimators[i] == se {
43+
replicaEstimators = append(replicaEstimators[:i], replicaEstimators[i+1:]...)
44+
i--
45+
}
46+
}
47+
for i := 0; i < len(unschedulableReplicaEstimators); i++ {
48+
if unschedulableReplicaEstimators[i] == se {
49+
unschedulableReplicaEstimators = append(unschedulableReplicaEstimators[:i], unschedulableReplicaEstimators[i+1:]...)
50+
i--
51+
}
52+
}
3753
}
3854

3955
type getClusterReplicasFunc func(ctx context.Context, cluster string) (int32, error)
@@ -67,6 +83,10 @@ func (se *SchedulerEstimator) MaxAvailableReplicas(
6783
})
6884
}
6985

86+
func (se *SchedulerEstimator) GetPriority() EstimatorPriority {
87+
return Accurate
88+
}
89+
7090
// GetUnschedulableReplicas gets the unschedulable replicas which belong to a specified workload by calling karmada-scheduler-estimator.
7191
func (se *SchedulerEstimator) GetUnschedulableReplicas(
7292
parentCtx context.Context,

pkg/estimator/client/general.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import (
3232

3333
// GeneralEstimator is the default replica estimator.
3434
func init() {
35-
replicaEstimators["general-estimator"] = NewGeneralEstimator()
35+
replicaEstimators = append(replicaEstimators, NewGeneralEstimator())
3636
}
3737

3838
// GeneralEstimator is a normal estimator in terms of cluster ResourceSummary.
@@ -53,6 +53,10 @@ func (ge *GeneralEstimator) MaxAvailableReplicas(_ context.Context, clusters []*
5353
return availableTargetClusters, nil
5454
}
5555

56+
func (ge *GeneralEstimator) GetPriority() EstimatorPriority {
57+
return General
58+
}
59+
5660
func (ge *GeneralEstimator) maxAvailableReplicas(cluster *clusterv1alpha1.Cluster, replicaRequirements *workv1alpha2.ReplicaRequirements) int32 {
5761
resourceSummary := cluster.Status.ResourceSummary
5862
if resourceSummary == nil {

pkg/estimator/client/interface.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,38 @@ import (
3030
const UnauthenticReplica = -1
3131

3232
var (
33-
replicaEstimators = map[string]ReplicaEstimator{}
34-
unschedulableReplicaEstimators = map[string]UnschedulableReplicaEstimator{}
33+
replicaEstimators []ReplicaEstimator
34+
unschedulableReplicaEstimators []UnschedulableReplicaEstimator
3535
)
3636

3737
// ReplicaEstimator is an estimator which estimates the maximum replicas that can be applied to the target cluster.
3838
type ReplicaEstimator interface {
3939
MaxAvailableReplicas(ctx context.Context, clusters []*clusterv1alpha1.Cluster, replicaRequirements *workv1alpha2.ReplicaRequirements) ([]workv1alpha2.TargetCluster, error)
40+
GetPriority() EstimatorPriority
4041
}
4142

4243
// UnschedulableReplicaEstimator is an estimator which estimates the unschedulable replicas which belong to a specified workload.
4344
type UnschedulableReplicaEstimator interface {
4445
GetUnschedulableReplicas(ctx context.Context, clusters []string, reference *workv1alpha2.ObjectReference, unschedulableThreshold time.Duration) ([]workv1alpha2.TargetCluster, error)
46+
GetPriority() EstimatorPriority
4547
}
4648

4749
// GetReplicaEstimators returns all replica estimators.
48-
func GetReplicaEstimators() map[string]ReplicaEstimator {
50+
func GetReplicaEstimators() []ReplicaEstimator {
4951
return replicaEstimators
5052
}
5153

5254
// GetUnschedulableReplicaEstimators returns all unschedulable replica estimators.
53-
func GetUnschedulableReplicaEstimators() map[string]UnschedulableReplicaEstimator {
55+
func GetUnschedulableReplicaEstimators() []UnschedulableReplicaEstimator {
5456
return unschedulableReplicaEstimators
5557
}
58+
59+
// EstimatorPriority
60+
// 1. If two estimators are of the same priority, call both and choose the minimum value of each estimated result.
61+
// 2. If higher-priority estimators have formed a full result of member clusters, no longer to call lower-priority estimator.
62+
type EstimatorPriority int32
63+
64+
const (
65+
General EstimatorPriority = 10
66+
Accurate EstimatorPriority = 20
67+
)

pkg/scheduler/core/util.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"math"
23+
"sort"
2324

2425
"k8s.io/apimachinery/pkg/util/sets"
2526
"k8s.io/klog/v2"
@@ -68,20 +69,33 @@ func calAvailableReplicas(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha
6869
return availableTargetClusters
6970
}
7071

71-
// Get the minimum value of MaxAvailableReplicas in terms of all estimators.
72+
// get estimators and sort it by priority.
7273
estimators := estimatorclient.GetReplicaEstimators()
74+
sort.Slice(estimators, func(i, j int) bool {
75+
return estimators[i].GetPriority() > estimators[j].GetPriority()
76+
})
77+
78+
priorityOfAvailableEstimator := estimatorclient.EstimatorPriority(math.MinInt32)
7379
ctx := context.WithValue(context.TODO(), util.ContextKeyObject,
7480
fmt.Sprintf("kind=%s, name=%s/%s", spec.Resource.Kind, spec.Resource.Namespace, spec.Resource.Name))
81+
7582
for _, estimator := range estimators {
83+
// if higher-priority estimators have formed a full result of member clusters, no longer to call lower-priority estimator.
84+
if estimator.GetPriority() < priorityOfAvailableEstimator && ClustersFullyEstimated(availableTargetClusters) {
85+
break
86+
}
7687
res, err := estimator.MaxAvailableReplicas(ctx, clusters, spec.ReplicaRequirements)
7788
if err != nil {
7889
klog.Errorf("Max cluster available replicas error: %v", err)
7990
continue
8091
}
92+
priorityOfAvailableEstimator = estimator.GetPriority()
8193
for i := range res {
94+
// if an estimator can only give a part of result of member clusters, same priority estimator will be called.
8295
if res[i].Replicas == estimatorclient.UnauthenticReplica {
8396
continue
8497
}
98+
// if two estimators are of the same priority, call both and choose the minimum value of each estimated result.
8599
if availableTargetClusters[i].Name == res[i].Name && availableTargetClusters[i].Replicas > res[i].Replicas {
86100
availableTargetClusters[i].Replicas = res[i].Replicas
87101
}
@@ -100,6 +114,16 @@ func calAvailableReplicas(clusters []*clusterv1alpha1.Cluster, spec *workv1alpha
100114
return availableTargetClusters
101115
}
102116

117+
// ClustersFullyEstimated whether estimators has gaven a full result of member clusters
118+
func ClustersFullyEstimated(availableTargetClusters []workv1alpha2.TargetCluster) bool {
119+
for i := range availableTargetClusters {
120+
if availableTargetClusters[i].Replicas == math.MaxInt32 {
121+
return false
122+
}
123+
}
124+
return true
125+
}
126+
103127
// attachZeroReplicasCluster attach cluster in clusters into targetCluster
104128
// The purpose is to avoid workload not appeared in rb's spec.clusters field
105129
func attachZeroReplicasCluster(clusters []*clusterv1alpha1.Cluster, targetClusters []workv1alpha2.TargetCluster) []workv1alpha2.TargetCluster {

0 commit comments

Comments
 (0)