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)
}
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.

View File

@ -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")
}
}

View File

@ -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 {
@ -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
@ -124,6 +129,7 @@ func NewPredicateChecker(kubeClient kube_client.Interface, stop <-chan struct{})
return &PredicateChecker{
predicates: predicateList,
predicateMetadataProducer: metadataProducer,
enableAffinityPredicate: true,
}, 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
// 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)
}
@ -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) {