Merge pull request #89162 from alculquicondor/affinity-less-lock

Reduce locking when calculating affinity scores
This commit is contained in:
Kubernetes Prow Robot 2020-03-19 15:04:35 -07:00 committed by GitHub
commit fe2fdcd695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -32,9 +32,11 @@ import (
// preScoreStateKey is the key in CycleState to InterPodAffinity pre-computed data for Scoring. // preScoreStateKey is the key in CycleState to InterPodAffinity pre-computed data for Scoring.
const preScoreStateKey = "PreScore" + Name const preScoreStateKey = "PreScore" + Name
type scoreMap map[string]map[string]int64
// preScoreState computed at PreScore and used at Score. // preScoreState computed at PreScore and used at Score.
type preScoreState struct { type preScoreState struct {
topologyScore map[string]map[string]int64 topologyScore scoreMap
affinityTerms []*weightedAffinityTerm affinityTerms []*weightedAffinityTerm
antiAffinityTerms []*weightedAffinityTerm antiAffinityTerms []*weightedAffinityTerm
} }
@ -76,8 +78,7 @@ func getWeightedAffinityTerms(pod *v1.Pod, v1Terms []v1.WeightedPodAffinityTerm)
return terms, nil return terms, nil
} }
func (pl *InterPodAffinity) processTerm( func (m scoreMap) processTerm(
state *preScoreState,
term *weightedAffinityTerm, term *weightedAffinityTerm,
podToCheck *v1.Pod, podToCheck *v1.Pod,
fixedNode *v1.Node, fixedNode *v1.Node,
@ -90,24 +91,34 @@ func (pl *InterPodAffinity) processTerm(
match := schedutil.PodMatchesTermsNamespaceAndSelector(podToCheck, term.namespaces, term.selector) match := schedutil.PodMatchesTermsNamespaceAndSelector(podToCheck, term.namespaces, term.selector)
tpValue, tpValueExist := fixedNode.Labels[term.topologyKey] tpValue, tpValueExist := fixedNode.Labels[term.topologyKey]
if match && tpValueExist { if match && tpValueExist {
pl.Lock() if m[term.topologyKey] == nil {
if state.topologyScore[term.topologyKey] == nil { m[term.topologyKey] = make(map[string]int64)
state.topologyScore[term.topologyKey] = make(map[string]int64)
} }
state.topologyScore[term.topologyKey][tpValue] += int64(term.weight * int32(multiplier)) m[term.topologyKey][tpValue] += int64(term.weight * int32(multiplier))
pl.Unlock()
} }
return return
} }
func (pl *InterPodAffinity) processTerms(state *preScoreState, terms []*weightedAffinityTerm, podToCheck *v1.Pod, fixedNode *v1.Node, multiplier int) error { func (m scoreMap) processTerms(terms []*weightedAffinityTerm, podToCheck *v1.Pod, fixedNode *v1.Node, multiplier int) {
for _, term := range terms { for _, term := range terms {
pl.processTerm(state, term, podToCheck, fixedNode, multiplier) m.processTerm(term, podToCheck, fixedNode, multiplier)
} }
return nil
} }
func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod *v1.Pod, existingPodNodeInfo *nodeinfo.NodeInfo, incomingPod *v1.Pod) error { func (m scoreMap) append(other scoreMap) {
for topology, oScores := range other {
scores := m[topology]
if scores == nil {
m[topology] = oScores
continue
}
for k, v := range oScores {
scores[k] += v
}
}
}
func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod *v1.Pod, existingPodNodeInfo *nodeinfo.NodeInfo, incomingPod *v1.Pod, topoScore scoreMap) error {
existingPodAffinity := existingPod.Spec.Affinity existingPodAffinity := existingPod.Spec.Affinity
existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil
existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil
@ -116,12 +127,12 @@ func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod
// For every soft pod affinity term of <pod>, if <existingPod> matches the term, // For every soft pod affinity term of <pod>, if <existingPod> matches the term,
// increment <p.counts> for every node in the cluster with the same <term.TopologyKey> // increment <p.counts> for every node in the cluster with the same <term.TopologyKey>
// value as that of <existingPods>`s node by the term`s weight. // value as that of <existingPods>`s node by the term`s weight.
pl.processTerms(state, state.affinityTerms, existingPod, existingPodNode, 1) topoScore.processTerms(state.affinityTerms, existingPod, existingPodNode, 1)
// For every soft pod anti-affinity term of <pod>, if <existingPod> matches the term, // For every soft pod anti-affinity term of <pod>, if <existingPod> matches the term,
// decrement <p.counts> for every node in the cluster with the same <term.TopologyKey> // decrement <p.counts> for every node in the cluster with the same <term.TopologyKey>
// value as that of <existingPod>`s node by the term`s weight. // value as that of <existingPod>`s node by the term`s weight.
pl.processTerms(state, state.antiAffinityTerms, existingPod, existingPodNode, -1) topoScore.processTerms(state.antiAffinityTerms, existingPod, existingPodNode, -1)
if existingHasAffinityConstraints { if existingHasAffinityConstraints {
// For every hard pod affinity term of <existingPod>, if <pod> matches the term, // For every hard pod affinity term of <existingPod>, if <pod> matches the term,
@ -139,7 +150,7 @@ func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod
if err != nil { if err != nil {
return err return err
} }
pl.processTerm(state, processedTerm, incomingPod, existingPodNode, 1) topoScore.processTerm(processedTerm, incomingPod, existingPodNode, 1)
} }
} }
// For every soft pod affinity term of <existingPod>, if <pod> matches the term, // For every soft pod affinity term of <existingPod>, if <pod> matches the term,
@ -151,7 +162,7 @@ func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod
return nil return nil
} }
pl.processTerms(state, terms, incomingPod, existingPodNode, 1) topoScore.processTerms(terms, incomingPod, existingPodNode, 1)
} }
if existingHasAntiAffinityConstraints { if existingHasAntiAffinityConstraints {
// For every soft pod anti-affinity term of <existingPod>, if <pod> matches the term, // For every soft pod anti-affinity term of <existingPod>, if <pod> matches the term,
@ -161,7 +172,7 @@ func (pl *InterPodAffinity) processExistingPod(state *preScoreState, existingPod
if err != nil { if err != nil {
return err return err
} }
pl.processTerms(state, terms, incomingPod, existingPodNode, -1) topoScore.processTerms(terms, incomingPod, existingPodNode, -1)
} }
return nil return nil
} }
@ -235,12 +246,18 @@ func (pl *InterPodAffinity) PreScore(
podsToProcess = nodeInfo.Pods() podsToProcess = nodeInfo.Pods()
} }
topoScore := make(scoreMap)
for _, existingPod := range podsToProcess { for _, existingPod := range podsToProcess {
if err := pl.processExistingPod(state, existingPod, nodeInfo, pod); err != nil { if err := pl.processExistingPod(state, existingPod, nodeInfo, pod, topoScore); err != nil {
errCh.SendErrorWithCancel(err, cancel) errCh.SendErrorWithCancel(err, cancel)
return return
} }
} }
if len(topoScore) > 0 {
pl.Lock()
state.topologyScore.append(topoScore)
pl.Unlock()
}
} }
workqueue.ParallelizeUntil(ctx, 16, len(allNodes), processNode) workqueue.ParallelizeUntil(ctx, 16, len(allNodes), processNode)
if err := errCh.ReceiveError(); err != nil { if err := errCh.ReceiveError(); err != nil {