Merge pull request #2827 from Garrybest/pr_alg

refactor assign replicas strategy
This commit is contained in:
karmada-bot 2022-11-22 14:36:05 +08:00 committed by GitHub
commit 9fc2c4cd6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 26 deletions

View File

@ -0,0 +1,64 @@
package core
import (
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
)
var (
assignFuncMap = map[string]func(*assignState) ([]workv1alpha2.TargetCluster, error){
DuplicatedStrategy: assignByDuplicatedStrategy,
AggregatedStrategy: assignByAggregatedStrategy,
StaticWeightStrategy: assignByStaticWeightStrategy,
DynamicWeightStrategy: assignByDynamicWeightStrategy,
}
)
// assignState is a wrapper of the input for assigning function.
type assignState struct {
candidates []*clusterv1alpha1.Cluster
strategy *policyv1alpha1.ReplicaSchedulingStrategy
object *workv1alpha2.ResourceBindingSpec
}
const (
// DuplicatedStrategy indicates each candidate member cluster will directly apply the original replicas.
DuplicatedStrategy = "Duplicated"
// AggregatedStrategy indicates dividing replicas among clusters as few as possible and
// taking clusters' available replicas into consideration as well.
AggregatedStrategy = "Aggregated"
// StaticWeightStrategy indicates dividing replicas by static weight according to WeightPreference.
StaticWeightStrategy = "StaticWeight"
// DynamicWeightStrategy indicates dividing replicas by dynamic weight according to WeightPreference.
DynamicWeightStrategy = "DynamicWeight"
)
// assignByDuplicatedStrategy assigns replicas by DuplicatedStrategy.
func assignByDuplicatedStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
targetClusters := make([]workv1alpha2.TargetCluster, len(state.candidates))
for i, cluster := range state.candidates {
targetClusters[i] = workv1alpha2.TargetCluster{Name: cluster.Name, Replicas: state.object.Replicas}
}
return targetClusters, nil
}
// assignByAggregatedStrategy assigns replicas by AggregatedStrategy.
func assignByAggregatedStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
return divideReplicasByResource(state.candidates, state.object, policyv1alpha1.ReplicaDivisionPreferenceAggregated)
}
// assignByStaticWeightStrategy assigns replicas by StaticWeightStrategy.
func assignByStaticWeightStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
// If ReplicaDivisionPreference is set to "Weighted" and WeightPreference is not set,
// scheduler will weight all clusters averagely.
if state.strategy.WeightPreference == nil {
state.strategy.WeightPreference = getDefaultWeightPreference(state.candidates)
}
return divideReplicasByStaticWeight(state.candidates, state.strategy.WeightPreference.StaticWeightList, state.object.Replicas)
}
// assignByDynamicWeightStrategy assigns replicas by assignByDynamicWeightStrategy.
func assignByDynamicWeightStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
return divideReplicasByDynamicWeight(state.candidates, state.strategy.WeightPreference.DynamicWeight, state.object)
}

View File

@ -173,46 +173,45 @@ func (g *genericScheduler) assignReplicas(
) ([]workv1alpha2.TargetCluster, error) {
startTime := time.Now()
defer metrics.ScheduleStep(metrics.ScheduleStepAssignReplicas, startTime)
if len(clusters) == 0 {
return nil, fmt.Errorf("no clusters available to schedule")
}
targetClusters := make([]workv1alpha2.TargetCluster, len(clusters))
if object.Replicas > 0 && replicaSchedulingStrategy != nil {
var strategy string
switch replicaSchedulingStrategy.ReplicaSchedulingType {
// 1. Duplicated Scheduling
case policyv1alpha1.ReplicaSchedulingTypeDuplicated:
for i, cluster := range clusters {
targetClusters[i] = workv1alpha2.TargetCluster{Name: cluster.Name, Replicas: object.Replicas}
}
return targetClusters, nil
// 2. Divided Scheduling
strategy = DuplicatedStrategy
case policyv1alpha1.ReplicaSchedulingTypeDivided:
switch replicaSchedulingStrategy.ReplicaDivisionPreference {
// 2.1 Weighted Scheduling
case policyv1alpha1.ReplicaDivisionPreferenceWeighted:
// If ReplicaDivisionPreference is set to "Weighted" and WeightPreference is not set,
// scheduler will weight all clusters averagely.
if replicaSchedulingStrategy.WeightPreference == nil {
replicaSchedulingStrategy.WeightPreference = getDefaultWeightPreference(clusters)
}
// 2.1.1 Dynamic Weighted Scheduling (by resource)
if len(replicaSchedulingStrategy.WeightPreference.DynamicWeight) != 0 {
return divideReplicasByDynamicWeight(clusters, replicaSchedulingStrategy.WeightPreference.DynamicWeight, object)
}
// 2.1.2 Static Weighted Scheduling
return divideReplicasByStaticWeight(clusters, replicaSchedulingStrategy.WeightPreference.StaticWeightList, object.Replicas)
// 2.2 Aggregated scheduling (by resource)
case policyv1alpha1.ReplicaDivisionPreferenceAggregated:
return divideReplicasByResource(clusters, object, policyv1alpha1.ReplicaDivisionPreferenceAggregated)
default:
return nil, fmt.Errorf("undefined replica division preference: %s", replicaSchedulingStrategy.ReplicaDivisionPreference)
strategy = AggregatedStrategy
case policyv1alpha1.ReplicaDivisionPreferenceWeighted:
if replicaSchedulingStrategy.WeightPreference != nil && len(replicaSchedulingStrategy.WeightPreference.DynamicWeight) != 0 {
strategy = DynamicWeightStrategy
} else {
strategy = StaticWeightStrategy
}
}
default:
return nil, fmt.Errorf("undefined replica scheduling type: %s", replicaSchedulingStrategy.ReplicaSchedulingType)
}
assign, ok := assignFuncMap[strategy]
if !ok {
// should never happen at present
return nil, fmt.Errorf("unsupported replica scheduling strategy, replicaSchedulingType: %s, replicaDivisionPreference: %s, "+
"please try another scheduling strategy", replicaSchedulingStrategy.ReplicaSchedulingType, replicaSchedulingStrategy.ReplicaDivisionPreference)
}
return assign(&assignState{
candidates: clusters,
strategy: replicaSchedulingStrategy,
object: object,
})
}
// If not workload, assign all clusters without considering replicas.
targetClusters := make([]workv1alpha2.TargetCluster, len(clusters))
for i, cluster := range clusters {
targetClusters[i] = workv1alpha2.TargetCluster{Name: cluster.Name}
}