Merge pull request #281 from MaciekPytel/disable_affinity_predicate

Disable MatchInterPodAffinity if there are no pods using affinity
This commit is contained in:
Marcin Wielgus 2017-08-31 16:50:33 +05:30 committed by GitHub
commit 7c1aa113f8
3 changed files with 50 additions and 0 deletions

View File

@ -187,6 +187,8 @@ func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError
return errors.ToAutoscalerError(errors.ApiCallError, err) return errors.ToAutoscalerError(errors.ApiCallError, err)
} }
ConfigurePredicateCheckerForLoop(allUnschedulablePods, allScheduled, a.PredicateChecker)
// We need to check whether pods marked as unschedulable are actually unschedulable. // 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 // 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. // pod on in yet. In this situation we don't want to trigger another scale-up.

View File

@ -387,3 +387,27 @@ func getPotentiallyUnneededNodes(context *AutoscalingContext, nodes []*apiv1.Nod
} }
return result 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")
}
}

View File

@ -46,6 +46,10 @@ const (
// This significantly improves performance and is useful if the error message // This significantly improves performance and is useful if the error message
// is discarded anyway. // is discarded anyway.
ReturnSimpleError ErrorVerbosity = false ReturnSimpleError ErrorVerbosity = false
// We want to disable affinity predicate for performance reasons if no ppod
// requires it
affinityPredicateName = "MatchInterPodAffinity"
) )
type predicateInfo struct { type predicateInfo struct {
@ -57,6 +61,7 @@ type predicateInfo struct {
type PredicateChecker struct { type PredicateChecker struct {
predicates []predicateInfo predicates []predicateInfo
predicateMetadataProducer algorithm.MetadataProducer predicateMetadataProducer algorithm.MetadataProducer
enableAffinityPredicate bool
} }
// there are no const arrays in go, this is meant to be used as a const // there are no const arrays in go, this is meant to be used as a const
@ -124,6 +129,7 @@ func NewPredicateChecker(kubeClient kube_client.Interface, stop <-chan struct{})
return &PredicateChecker{ return &PredicateChecker{
predicates: predicateList, predicates: predicateList,
predicateMetadataProducer: metadataProducer, predicateMetadataProducer: metadataProducer,
enableAffinityPredicate: true,
}, nil }, nil
} }
@ -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 // 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 // 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 // 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. // 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. // 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{} { 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) return p.predicateMetadataProducer(pod, nodeInfos)
} }
@ -183,6 +201,12 @@ func (p *PredicateChecker) FitsAny(pod *apiv1.Pod, nodeInfos map[string]*schedul
// Alternatively you can pass nil as predicateMetadata. // Alternatively you can pass nil as predicateMetadata.
func (p *PredicateChecker) CheckPredicates(pod *apiv1.Pod, predicateMetadata interface{}, nodeInfo *schedulercache.NodeInfo, verbosity ErrorVerbosity) error { func (p *PredicateChecker) CheckPredicates(pod *apiv1.Pod, predicateMetadata interface{}, nodeInfo *schedulercache.NodeInfo, verbosity ErrorVerbosity) error {
for _, predInfo := range p.predicates { 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) match, failureReason, err := predInfo.predicate(pod, predicateMetadata, nodeInfo)
if verbosity == ReturnSimpleError && (err != nil || !match) { if verbosity == ReturnSimpleError && (err != nil || !match) {