Skip to content

Commit cb753d5

Browse files
serathiusk8s-publishing-bot
authored andcommitted
Disable estimating resource size for resources with watch cache disabled
Listing all keys from etcd turned out to be too expensive, negativly impacting events POST latency. Events resource is the only resource that by default has watch cache disabled and which includes very large number of small objects making it very costly to list keys. Expected impact: * No apiserver_resource_size_estimate_bytes metric for events. * APF overestimating LIST request cost to events. Fallback assumes object size of 1.5MB, meaning LIST events will always get maxSeats Kubernetes-commit: f779cf6381917267aa54460b7e66b9a7cc165677
1 parent 72857c3 commit cb753d5

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

pkg/storage/etcd3/stats.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package etcd3
1818

1919
import (
2020
"context"
21+
"errors"
2122
"strings"
2223
"sync"
2324

@@ -78,6 +79,8 @@ type sizeRevision struct {
7879
revision int64
7980
}
8081

82+
var errStatsDisabled = errors.New("key size stats disabled")
83+
8184
func (sc *statsCache) Stats(ctx context.Context) (storage.Stats, error) {
8285
keys, err := sc.GetKeys(ctx)
8386
if err != nil {
@@ -100,6 +103,9 @@ func (sc *statsCache) GetKeys(ctx context.Context) ([]string, error) {
100103
getKeys := sc.getKeys
101104
sc.getKeysLock.Unlock()
102105

106+
if getKeys == nil {
107+
return nil, errStatsDisabled
108+
}
103109
// Don't execute getKeys under lock.
104110
return getKeys(ctx)
105111
}
@@ -133,7 +139,10 @@ func (sc *statsCache) cleanKeysIfNeeded(ctx context.Context) {
133139
}
134140
keys, err := sc.GetKeys(ctx)
135141
if err != nil {
136-
klog.InfoS("Error getting keys", "err", err)
142+
if !errors.Is(err, errStatsDisabled) {
143+
klog.InfoS("Error getting keys", "err", err)
144+
}
145+
return
137146
}
138147
sc.keysLock.Lock()
139148
defer sc.keysLock.Unlock()

pkg/storage/etcd3/store.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func New(c *kubernetes.Client, compactor Compactor, codec runtime.Codec, newFunc
188188
}
189189
// Collecting stats requires properly set resourcePrefix to call getKeys.
190190
if resourcePrefix != "" && utilfeature.DefaultFeatureGate.Enabled(features.SizeBasedListCostEstimate) {
191-
stats := newStatsCache(pathPrefix, s.getKeys)
191+
stats := newStatsCache(pathPrefix, nil)
192192
s.stats = stats
193193
w.stats = stats
194194
}
@@ -632,7 +632,10 @@ func getNewItemFunc(listObj runtime.Object, v reflect.Value) func() runtime.Obje
632632

633633
func (s *store) Stats(ctx context.Context) (stats storage.Stats, err error) {
634634
if s.stats != nil {
635-
return s.stats.Stats(ctx)
635+
stats, err := s.stats.Stats(ctx)
636+
if !errors.Is(err, errStatsDisabled) {
637+
return stats, err
638+
}
636639
}
637640
startTime := time.Now()
638641
prefix, err := s.prepareKey(s.resourcePrefix)

pkg/storage/etcd3/store_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ func TestStats(t *testing.T) {
384384
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SizeBasedListCostEstimate, sizeBasedListCostEstimate)
385385
// Match transformer with cacher tests.
386386
ctx, store, _ := testSetup(t)
387+
store.SetKeysFunc(store.getKeys)
387388
storagetesting.RunTestStats(ctx, t, store, store.codec, store.transformer, sizeBasedListCostEstimate)
388389
})
389390
}
@@ -1041,15 +1042,30 @@ func TestPrefixStats(t *testing.T) {
10411042
tcs := []struct {
10421043
name string
10431044
estimate bool
1045+
setKeys bool
10441046
expectStats storage.Stats
10451047
}{
10461048
{
1047-
name: "SizeBasedListCostEstimate=false",
1049+
name: "SizeBasedListCostEstimate=false,SetKeys=false",
1050+
setKeys: false,
10481051
estimate: false,
10491052
expectStats: storage.Stats{ObjectCount: 1},
10501053
},
10511054
{
1052-
name: "SizeBasedListCostEstimate=true",
1055+
name: "SizeBasedListCostEstimate=false,SetKeys=true",
1056+
setKeys: true,
1057+
estimate: false,
1058+
expectStats: storage.Stats{ObjectCount: 1},
1059+
},
1060+
{
1061+
name: "SizeBasedListCostEstimate=true,SetKeys=false",
1062+
setKeys: false,
1063+
estimate: true,
1064+
expectStats: storage.Stats{ObjectCount: 1},
1065+
},
1066+
{
1067+
name: "SizeBasedListCostEstimate=true,SetKeys=true",
1068+
setKeys: true,
10531069
estimate: true,
10541070
expectStats: storage.Stats{ObjectCount: 1, EstimatedAverageObjectSizeBytes: 3},
10551071
},
@@ -1058,6 +1074,9 @@ func TestPrefixStats(t *testing.T) {
10581074
t.Run(tc.name, func(t *testing.T) {
10591075
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SizeBasedListCostEstimate, tc.estimate)
10601076
ctx, store, c := testSetup(t, withPrefix("/registry"), withResourcePrefix("pods"))
1077+
if tc.setKeys {
1078+
store.SetKeysFunc(store.getKeys)
1079+
}
10611080
_, err := c.KV.Put(ctx, "key", "a")
10621081
if err != nil {
10631082
t.Fatal(err)

0 commit comments

Comments
 (0)