Skip to content

Commit

Permalink
Merge pull request #281 from MaciekPytel/disable_affinity_predicate
Browse files Browse the repository at this point in the history
Disable MatchInterPodAffinity if there are no pods using affinity
  • Loading branch information
mwielgus authored Aug 31, 2017
2 parents 4a3b293 + 69c5ea0 commit 7c1aa11
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cluster-autoscaler/core/static_autoscaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError
return errors.ToAutoscalerError(errors.ApiCallError, err)
}

ConfigurePredicateCheckerForLoop(allUnschedulablePods, allScheduled, a.PredicateChecker)

// We need to check whether pods marked as unschedulable are actually unschedulable.
// It's likely we added a new node and the scheduler just haven't managed to put the
// pod on in yet. In this situation we don't want to trigger another scale-up.
Expand Down
24 changes: 24 additions & 0 deletions cluster-autoscaler/core/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,27 @@ func getPotentiallyUnneededNodes(context *AutoscalingContext, nodes []*apiv1.Nod
}
return result
}

// ConfigurePredicateCheckerForLoop can be run to update predicateChecker configuration
// based on current state of the cluster.
func ConfigurePredicateCheckerForLoop(unschedulablePods []*apiv1.Pod, schedulablePods []*apiv1.Pod, predicateChecker *simulator.PredicateChecker) {
podsWithAffinityFound := false
for _, pod := range unschedulablePods {
if pod.Spec.Affinity != nil {
podsWithAffinityFound = true
break
}
}
if !podsWithAffinityFound {
for _, pod := range schedulablePods {
if pod.Spec.Affinity != nil {
podsWithAffinityFound = true
break
}
}
}
predicateChecker.SetAffinityPredicateEnabled(podsWithAffinityFound)
if !podsWithAffinityFound {
glog.V(1).Info("No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop")
}
}
24 changes: 24 additions & 0 deletions cluster-autoscaler/simulator/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const (
// This significantly improves performance and is useful if the error message
// is discarded anyway.
ReturnSimpleError ErrorVerbosity = false

// We want to disable affinity predicate for performance reasons if no ppod
// requires it
affinityPredicateName = "MatchInterPodAffinity"
)

type predicateInfo struct {
Expand All @@ -57,6 +61,7 @@ type predicateInfo struct {
type PredicateChecker struct {
predicates []predicateInfo
predicateMetadataProducer algorithm.MetadataProducer
enableAffinityPredicate bool
}

// there are no const arrays in go, this is meant to be used as a const
Expand Down Expand Up @@ -124,6 +129,7 @@ func NewPredicateChecker(kubeClient kube_client.Interface, stop <-chan struct{})
return &PredicateChecker{
predicates: predicateList,
predicateMetadataProducer: metadataProducer,
enableAffinityPredicate: true,
}, nil
}

Expand All @@ -149,12 +155,24 @@ func NewTestPredicateChecker() *PredicateChecker {
}
}

// SetAffinityPredicateEnabled can be used to enable or disable checking MatchInterPodAffinity
// predicate. This will cause incorrect CA behavior if there is at least a single pod in
// cluster using affinity/antiaffinity. However, checking affinity predicate is extremly
// costly even if no pod is using it, so it may be worth disabling it in such situation.
func (p *PredicateChecker) SetAffinityPredicateEnabled(enable bool) {
p.enableAffinityPredicate = enable
}

// GetPredicateMetadata precomputes some information useful for running predicates on a given pod in a given state
// of the cluster (represented by nodeInfos map). Passing the result of this function to CheckPredicates can significantly
// improve the performance of running predicates, especially MatchInterPodAffinity predicate. However, calculating
// predicateMetadata is also quite expensive, so it's not always the best option to run this method.
// Please refer to https://github.com/kubernetes/autoscaler/issues/257 for more details.
func (p *PredicateChecker) GetPredicateMetadata(pod *apiv1.Pod, nodeInfos map[string]*schedulercache.NodeInfo) interface{} {
// skip precomputation if affinity predicate is disabled - it's not worth it performance wise
if !p.enableAffinityPredicate {
return nil
}
return p.predicateMetadataProducer(pod, nodeInfos)
}

Expand Down Expand Up @@ -183,6 +201,12 @@ func (p *PredicateChecker) FitsAny(pod *apiv1.Pod, nodeInfos map[string]*schedul
// Alternatively you can pass nil as predicateMetadata.
func (p *PredicateChecker) CheckPredicates(pod *apiv1.Pod, predicateMetadata interface{}, nodeInfo *schedulercache.NodeInfo, verbosity ErrorVerbosity) error {
for _, predInfo := range p.predicates {

// skip affinity predicate if it has been disabled
if !p.enableAffinityPredicate && predInfo.name == affinityPredicateName {
continue
}

match, failureReason, err := predInfo.predicate(pod, predicateMetadata, nodeInfo)

if verbosity == ReturnSimpleError && (err != nil || !match) {
Expand Down

0 comments on commit 7c1aa11

Please sign in to comment.