mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #63603 from resouer/clean-cache
Automatic merge from submit-queue (batch tested with PRs 63603, 63557, 62015). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Clean up equiv cache with a simple implementation instead of LRU **What this PR does / why we need it**: The original version of equiv cache use pod hash as cache key, also, the predicate order is not fixed. So I used a LRU cache to improve hit rate. While now we've already refactored it to use predicates as keys, and its order was also fixed in scheduler, we can use a simplest cache instead now. **Special notes for your reviewer**: The question is brought up by @misterikkit **Release note**: ```release-note NONE ```
This commit is contained in:
commit
c4994e17d6
@ -57,7 +57,6 @@ go_library(
|
|||||||
"//pkg/scheduler/volumebinder:go_default_library",
|
"//pkg/scheduler/volumebinder:go_default_library",
|
||||||
"//pkg/util/hash:go_default_library",
|
"//pkg/util/hash:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/github.com/golang/groupcache/lru:go_default_library",
|
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -28,12 +28,8 @@ import (
|
|||||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/golang/groupcache/lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// We use predicate names as cache's key, its count is limited
|
|
||||||
const maxCacheEntries = 100
|
|
||||||
|
|
||||||
// EquivalenceCache holds:
|
// EquivalenceCache holds:
|
||||||
// 1. a map of AlgorithmCache with node name as key
|
// 1. a map of AlgorithmCache with node name as key
|
||||||
// 2. function to get equivalence pod
|
// 2. function to get equivalence pod
|
||||||
@ -42,11 +38,8 @@ type EquivalenceCache struct {
|
|||||||
algorithmCache map[string]AlgorithmCache
|
algorithmCache map[string]AlgorithmCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// The AlgorithmCache stores PredicateMap with predicate name as key
|
// The AlgorithmCache stores PredicateMap with predicate name as key, PredicateMap as value.
|
||||||
type AlgorithmCache struct {
|
type AlgorithmCache map[string]PredicateMap
|
||||||
// Only consider predicates for now
|
|
||||||
predicatesCache *lru.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredicateMap stores HostPrediacte with equivalence hash as key
|
// PredicateMap stores HostPrediacte with equivalence hash as key
|
||||||
type PredicateMap map[uint64]HostPredicate
|
type PredicateMap map[uint64]HostPredicate
|
||||||
@ -57,12 +50,6 @@ type HostPredicate struct {
|
|||||||
FailReasons []algorithm.PredicateFailureReason
|
FailReasons []algorithm.PredicateFailureReason
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAlgorithmCache() AlgorithmCache {
|
|
||||||
return AlgorithmCache{
|
|
||||||
predicatesCache: lru.New(maxCacheEntries),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEquivalenceCache returns EquivalenceCache to speed up predicates by caching
|
// NewEquivalenceCache returns EquivalenceCache to speed up predicates by caching
|
||||||
// result from previous scheduling.
|
// result from previous scheduling.
|
||||||
func NewEquivalenceCache() *EquivalenceCache {
|
func NewEquivalenceCache() *EquivalenceCache {
|
||||||
@ -109,22 +96,21 @@ func (ec *EquivalenceCache) updateResult(
|
|||||||
equivalenceHash uint64,
|
equivalenceHash uint64,
|
||||||
) {
|
) {
|
||||||
if _, exist := ec.algorithmCache[nodeName]; !exist {
|
if _, exist := ec.algorithmCache[nodeName]; !exist {
|
||||||
ec.algorithmCache[nodeName] = newAlgorithmCache()
|
ec.algorithmCache[nodeName] = AlgorithmCache{}
|
||||||
}
|
}
|
||||||
predicateItem := HostPredicate{
|
predicateItem := HostPredicate{
|
||||||
Fit: fit,
|
Fit: fit,
|
||||||
FailReasons: reasons,
|
FailReasons: reasons,
|
||||||
}
|
}
|
||||||
// if cached predicate map already exists, just update the predicate by key
|
// if cached predicate map already exists, just update the predicate by key
|
||||||
if v, ok := ec.algorithmCache[nodeName].predicatesCache.Get(predicateKey); ok {
|
if predicateMap, ok := ec.algorithmCache[nodeName][predicateKey]; ok {
|
||||||
predicateMap := v.(PredicateMap)
|
|
||||||
// maps in golang are references, no need to add them back
|
// maps in golang are references, no need to add them back
|
||||||
predicateMap[equivalenceHash] = predicateItem
|
predicateMap[equivalenceHash] = predicateItem
|
||||||
} else {
|
} else {
|
||||||
ec.algorithmCache[nodeName].predicatesCache.Add(predicateKey,
|
ec.algorithmCache[nodeName][predicateKey] =
|
||||||
PredicateMap{
|
PredicateMap{
|
||||||
equivalenceHash: predicateItem,
|
equivalenceHash: predicateItem,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
glog.V(5).Infof("Updated cached predicate: %v for pod: %v on node: %s, with item %v", predicateKey, podName, nodeName, predicateItem)
|
glog.V(5).Infof("Updated cached predicate: %v for pod: %v on node: %s, with item %v", predicateKey, podName, nodeName, predicateItem)
|
||||||
}
|
}
|
||||||
@ -139,11 +125,7 @@ func (ec *EquivalenceCache) lookupResult(
|
|||||||
) (bool, []algorithm.PredicateFailureReason, bool) {
|
) (bool, []algorithm.PredicateFailureReason, bool) {
|
||||||
glog.V(5).Infof("Begin to calculate predicate: %v for pod: %s on node: %s based on equivalence cache",
|
glog.V(5).Infof("Begin to calculate predicate: %v for pod: %s on node: %s based on equivalence cache",
|
||||||
predicateKey, podName, nodeName)
|
predicateKey, podName, nodeName)
|
||||||
if algorithmCache, exist := ec.algorithmCache[nodeName]; exist {
|
if hostPredicate, exist := ec.algorithmCache[nodeName][predicateKey][equivalenceHash]; exist {
|
||||||
if cachePredicate, exist := algorithmCache.predicatesCache.Get(predicateKey); exist {
|
|
||||||
predicateMap := cachePredicate.(PredicateMap)
|
|
||||||
// TODO(resouer) Is it possible a race that cache failed to update immediately?
|
|
||||||
if hostPredicate, ok := predicateMap[equivalenceHash]; ok {
|
|
||||||
if hostPredicate.Fit {
|
if hostPredicate.Fit {
|
||||||
return true, []algorithm.PredicateFailureReason{}, false
|
return true, []algorithm.PredicateFailureReason{}, false
|
||||||
}
|
}
|
||||||
@ -151,9 +133,6 @@ func (ec *EquivalenceCache) lookupResult(
|
|||||||
}
|
}
|
||||||
// is invalid
|
// is invalid
|
||||||
return false, []algorithm.PredicateFailureReason{}, true
|
return false, []algorithm.PredicateFailureReason{}, true
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, []algorithm.PredicateFailureReason{}, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvalidateCachedPredicateItem marks all items of given predicateKeys, of all pods, on the given node as invalid
|
// InvalidateCachedPredicateItem marks all items of given predicateKeys, of all pods, on the given node as invalid
|
||||||
@ -163,10 +142,8 @@ func (ec *EquivalenceCache) InvalidateCachedPredicateItem(nodeName string, predi
|
|||||||
}
|
}
|
||||||
ec.mu.Lock()
|
ec.mu.Lock()
|
||||||
defer ec.mu.Unlock()
|
defer ec.mu.Unlock()
|
||||||
if algorithmCache, exist := ec.algorithmCache[nodeName]; exist {
|
|
||||||
for predicateKey := range predicateKeys {
|
for predicateKey := range predicateKeys {
|
||||||
algorithmCache.predicatesCache.Remove(predicateKey)
|
delete(ec.algorithmCache[nodeName], predicateKey)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
glog.V(5).Infof("Done invalidating cached predicates: %v on node: %s", predicateKeys, nodeName)
|
glog.V(5).Infof("Done invalidating cached predicates: %v on node: %s", predicateKeys, nodeName)
|
||||||
}
|
}
|
||||||
@ -181,8 +158,7 @@ func (ec *EquivalenceCache) InvalidateCachedPredicateItemOfAllNodes(predicateKey
|
|||||||
// algorithmCache uses nodeName as key, so we just iterate it and invalid given predicates
|
// algorithmCache uses nodeName as key, so we just iterate it and invalid given predicates
|
||||||
for _, algorithmCache := range ec.algorithmCache {
|
for _, algorithmCache := range ec.algorithmCache {
|
||||||
for predicateKey := range predicateKeys {
|
for predicateKey := range predicateKeys {
|
||||||
// just use keys is enough
|
delete(algorithmCache, predicateKey)
|
||||||
algorithmCache.predicatesCache.Remove(predicateKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glog.V(5).Infof("Done invalidating cached predicates: %v on all node", predicateKeys)
|
glog.V(5).Infof("Done invalidating cached predicates: %v on all node", predicateKeys)
|
||||||
|
@ -345,14 +345,14 @@ func TestUpdateResult(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
ecache := NewEquivalenceCache()
|
ecache := NewEquivalenceCache()
|
||||||
if test.expectPredicateMap {
|
if test.expectPredicateMap {
|
||||||
ecache.algorithmCache[test.nodeName] = newAlgorithmCache()
|
ecache.algorithmCache[test.nodeName] = AlgorithmCache{}
|
||||||
predicateItem := HostPredicate{
|
predicateItem := HostPredicate{
|
||||||
Fit: true,
|
Fit: true,
|
||||||
}
|
}
|
||||||
ecache.algorithmCache[test.nodeName].predicatesCache.Add(test.predicateKey,
|
ecache.algorithmCache[test.nodeName][test.predicateKey] =
|
||||||
PredicateMap{
|
PredicateMap{
|
||||||
test.equivalenceHash: predicateItem,
|
test.equivalenceHash: predicateItem,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
ecache.mu.Lock()
|
ecache.mu.Lock()
|
||||||
ecache.updateResult(
|
ecache.updateResult(
|
||||||
@ -365,12 +365,11 @@ func TestUpdateResult(t *testing.T) {
|
|||||||
)
|
)
|
||||||
ecache.mu.Unlock()
|
ecache.mu.Unlock()
|
||||||
|
|
||||||
value, ok := ecache.algorithmCache[test.nodeName].predicatesCache.Get(test.predicateKey)
|
cachedMapItem, ok := ecache.algorithmCache[test.nodeName][test.predicateKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("Failed: %s, can't find expected cache item: %v",
|
t.Errorf("Failed: %s, can't find expected cache item: %v",
|
||||||
test.name, test.expectCacheItem)
|
test.name, test.expectCacheItem)
|
||||||
} else {
|
} else {
|
||||||
cachedMapItem := value.(PredicateMap)
|
|
||||||
if !reflect.DeepEqual(cachedMapItem[test.equivalenceHash], test.expectCacheItem) {
|
if !reflect.DeepEqual(cachedMapItem[test.equivalenceHash], test.expectCacheItem) {
|
||||||
t.Errorf("Failed: %s, expected cached item: %v, but got: %v",
|
t.Errorf("Failed: %s, expected cached item: %v, but got: %v",
|
||||||
test.name, test.expectCacheItem, cachedMapItem[test.equivalenceHash])
|
test.name, test.expectCacheItem, cachedMapItem[test.equivalenceHash])
|
||||||
@ -693,7 +692,7 @@ func TestInvalidateCachedPredicateItemOfAllNodes(t *testing.T) {
|
|||||||
// there should be no cached predicate any more
|
// there should be no cached predicate any more
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
if algorithmCache, exist := ecache.algorithmCache[test.nodeName]; exist {
|
if algorithmCache, exist := ecache.algorithmCache[test.nodeName]; exist {
|
||||||
if _, exist := algorithmCache.predicatesCache.Get(testPredicate); exist {
|
if _, exist := algorithmCache[testPredicate]; exist {
|
||||||
t.Errorf("Failed: cached item for predicate key: %v on node: %v should be invalidated",
|
t.Errorf("Failed: cached item for predicate key: %v on node: %v should be invalidated",
|
||||||
testPredicate, test.nodeName)
|
testPredicate, test.nodeName)
|
||||||
break
|
break
|
||||||
|
Loading…
Reference in New Issue
Block a user