Merge pull request #281 from MaciekPytel/disable_affinity_predicate
Disable MatchInterPodAffinity if there are no pods using affinity
This commit is contained in:
commit
7c1aa113f8
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue