Skip to content

Commit b1ad53c

Browse files
committed
Disable StorageNamespaceIndex feature gate when BtreeWatchCache is enabled and deprecate it
Previously, the cache used a map keyed by the full object key, requiring iteration and filtering by namespace for namespace-scoped requests. This index allowed for faster responses by avoiding this iteration. With the introduction of the BtreeWatchCache, this optimization is no longer necessary. The B-tree structure allows efficient prefix-based searches, including fetching objects by namespace. Furthermore, the B-tree returns elements ordered by key, eliminating the need for separate sorting. Performance improvements with the BtreeWatchCache have been validated through benchmarks matching K8s scalability dimentions (see table below). These results demonstrate that the B-tree approach provides comparable or better performance than the map with index. Therefore, the StorageNamespaceIndex feature flag can be safely flipped to false and subsequently deprecated. | Benchmark | Btree with Index (current) | Btree without Index | Map with Index | Map without Index (sanity check) | | --------------------------------------------------------------------------------- | -------------------------- | ---------------------- | ---------------------- | -------------------------------- | | StoreList (10k Namespaces, 150k Pods, 5k Nodes, RV=, Namespace Scope) | 20.77µs ± 10% | 20.14µs ± 13% (~0%) | 19.73µs ± 6% (~0%) | 1067.34µs ± 10% (+5037.73%) | | StoreList (10k Namespaces, 150k Pods, 5k Nodes, RV=NotOlderThan, Namespace Scope) | 3.943µs ± 6% | 3.928µs ± 6% (~0%) | 3.665µs ± 3% (-7.05%) | 944.641µs ± 1% (+23857.41%) | | StoreList (50 Namespaces, 150k Pods, 5k Nodes, RV=, Namespace Scope) | 303.3µs ± 2% | 258.2µs ± 2% (-14.85%) | 340.1µs ± 3% (+12.15%) | 1668.6µs ± 4% (+450.23%) | | StoreList (50 Namespaces, 150k Pods, 5k Nodes, RV=NotOlderThan, Namespace Scope) | 286.2µs ± 3% | 234.7µs ± 1% (-17.99%) | 326.9µs ± 2% (+14.22%) | 1347.7µs ± 4% (+370.91%) | | StoreList (100 Namespaces, 110k Pods, 1k Nodes, RV=, Namespace Scope) | 125.3µs ± 2% | 112.3µs ± 5% (-10.38%) | 137.5µs ± 2% (+9.81%) | 1395.1µs ± 8% (+1013.78%) | | StoreList (100 Namespaces, 110k Pods, 1k Nodes, RV=NotOlderThan, Namespace Scope) | 120.6µs ± 2% | 113.2µs ± 1% (-6.13%) | 133.8µs ± 1% (+10.92%) | 1719.1µs ± 5% (+1325.35%) | | Geometric Mean | 68.94µs | 62.73µs (-9.02%) | 72.72µs (+5.48%) | 1.326ms (+1823.40%) |
1 parent 3bc8f01 commit b1ad53c

File tree

4 files changed

+9
-2
lines changed

4 files changed

+9
-2
lines changed

pkg/features/kube_features.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@ const (
681681
// owner: @ahutsunshine
682682
//
683683
// Allows namespace indexer for namespace scope resources in apiserver cache to accelerate list operations.
684+
// Superseded by BtreeWatchCache.
684685
StorageNamespaceIndex featuregate.Feature = "StorageNamespaceIndex"
685686

686687
// owner: @nilekhc

pkg/features/versioned_kube_features.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
675675

676676
StorageNamespaceIndex: {
677677
{Version: version.MustParse("1.30"), Default: true, PreRelease: featuregate.Beta},
678+
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Deprecated},
678679
},
679680

680681
ServiceAccountNodeAudienceRestriction: {

pkg/registry/core/pod/strategy.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
utilnet "k8s.io/apimachinery/pkg/util/net"
4141
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
4242
"k8s.io/apimachinery/pkg/util/validation/field"
43+
apiserverfeatures "k8s.io/apiserver/pkg/features"
4344
"k8s.io/apiserver/pkg/registry/generic"
4445
"k8s.io/apiserver/pkg/storage"
4546
"k8s.io/apiserver/pkg/storage/names"
@@ -365,7 +366,7 @@ func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
365366
// MatchPod returns a generic matcher for a given label and field selector.
366367
func MatchPod(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
367368
var indexFields = []string{"spec.nodeName"}
368-
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) {
369+
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) && !utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.BtreeWatchCache) {
369370
indexFields = append(indexFields, "metadata.namespace")
370371
}
371372
return storage.SelectionPredicate{
@@ -404,7 +405,7 @@ func Indexers() *cache.Indexers {
404405
var indexers = cache.Indexers{
405406
storage.FieldIndex("spec.nodeName"): NodeNameIndexFunc,
406407
}
407-
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) {
408+
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) && !utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.BtreeWatchCache) {
408409
indexers[storage.FieldIndex("metadata.namespace")] = NamespaceIndexFunc
409410
}
410411
return &indexers

test/featuregates_linter/test_data/versioned_feature_list.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,10 @@
12861286
lockToDefault: false
12871287
preRelease: Beta
12881288
version: "1.30"
1289+
- default: true
1290+
lockToDefault: false
1291+
preRelease: Deprecated
1292+
version: "1.33"
12891293
- name: StorageVersionAPI
12901294
versionedSpecs:
12911295
- default: false

0 commit comments

Comments
 (0)