Skip to content

Commit 2eb99db

Browse files
committed
Add cache metrics
1 parent 7b9e012 commit 2eb99db

File tree

4 files changed

+77
-19
lines changed

4 files changed

+77
-19
lines changed

balancer/rls/balancer.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ var (
7979
dataCachePurgeHook = func() {}
8080
resetBackoffHook = func() {}
8181

82+
cacheEntriesMetric = estats.RegisterInt64Gauge(estats.MetricDescriptor{
83+
Name: "grpc.lb.rls.cache_entries",
84+
Description: "EXPERIMENTAL. Number of entries in the RLS cache.",
85+
Unit: "entry",
86+
Labels: []string{"grpc.target", "grpc.lb.rls.server_target", "grpc.lb.rls.instance_uuid"},
87+
Default: false,
88+
})
89+
cacheSizeMetric = estats.RegisterInt64Gauge(estats.MetricDescriptor{
90+
Name: "grpc.lb.rls.cache_size",
91+
Description: "EXPERIMENTAL. The current size of the RLS cache.",
92+
Unit: "By",
93+
Labels: []string{"grpc.target", "grpc.lb.rls.server_target", "grpc.lb.rls.instance_uuid"},
94+
Default: false,
95+
})
8296
defaultTargetPicksMetric = estats.RegisterInt64Count(estats.MetricDescriptor{
8397
Name: "grpc.lb.rls.default_target_picks",
8498
Description: "EXPERIMENTAL. Number of LB picks sent to the default target.",
@@ -126,7 +140,7 @@ func (rlsBB) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.
126140
updateCh: buffer.NewUnbounded(),
127141
}
128142
lb.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[rls-experimental-lb %p] ", lb))
129-
lb.dataCache = newDataCache(maxCacheSize, lb.logger)
143+
lb.dataCache = newDataCache(maxCacheSize, lb.logger, opts.MetricsRecorder, opts.Target.String())
130144
lb.bg = balancergroup.New(balancergroup.Options{
131145
CC: cc,
132146
BuildOpts: opts,
@@ -326,6 +340,7 @@ func (b *rlsBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error
326340
// `resizeCache` boolean) because `cacheMu` needs to be grabbed before
327341
// `stateMu` if we are to hold both locks at the same time.
328342
b.cacheMu.Lock()
343+
b.dataCache.updateRLSServerTarget(newCfg.lookupService)
329344
b.dataCache.resize(newCfg.cacheSizeBytes)
330345
b.cacheMu.Unlock()
331346
}

balancer/rls/cache.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"container/list"
2323
"time"
2424

25+
"github.com/google/uuid"
26+
estats "google.golang.org/grpc/experimental/stats"
2527
"google.golang.org/grpc/internal/backoff"
2628
internalgrpclog "google.golang.org/grpc/internal/grpclog"
2729
"google.golang.org/grpc/internal/grpcsync"
@@ -163,22 +165,40 @@ func (l *lru) getLeastRecentlyUsed() cacheKey {
163165
//
164166
// It is not safe for concurrent access.
165167
type dataCache struct {
166-
maxSize int64 // Maximum allowed size.
167-
currentSize int64 // Current size.
168-
keys *lru // Cache keys maintained in lru order.
169-
entries map[cacheKey]*cacheEntry
170-
logger *internalgrpclog.PrefixLogger
171-
shutdown *grpcsync.Event
168+
maxSize int64 // Maximum allowed size.
169+
currentSize int64 // Current size.
170+
keys *lru // Cache keys maintained in lru order.
171+
entries map[cacheKey]*cacheEntry
172+
logger *internalgrpclog.PrefixLogger
173+
shutdown *grpcsync.Event
174+
rlsServerTarget string
175+
176+
// Read only after initialization.
177+
grpcTarget string
178+
uuid string
179+
metricsRecorder estats.MetricsRecorder
172180
}
173181

174-
func newDataCache(size int64, logger *internalgrpclog.PrefixLogger) *dataCache {
175-
return &dataCache{
176-
maxSize: size,
177-
keys: newLRU(),
178-
entries: make(map[cacheKey]*cacheEntry),
179-
logger: logger,
180-
shutdown: grpcsync.NewEvent(),
182+
func newDataCache(size int64, logger *internalgrpclog.PrefixLogger, metricsRecorder estats.MetricsRecorder, grpcTarget string) *dataCache {
183+
dc := &dataCache{
184+
maxSize: size,
185+
keys: newLRU(),
186+
entries: make(map[cacheKey]*cacheEntry),
187+
logger: logger,
188+
shutdown: grpcsync.NewEvent(),
189+
grpcTarget: grpcTarget,
190+
uuid: uuid.New().String(),
191+
metricsRecorder: metricsRecorder,
181192
}
193+
cacheSizeMetric.Record(dc.metricsRecorder, 0, grpcTarget, "", dc.uuid)
194+
cacheEntriesMetric.Record(dc.metricsRecorder, 0, grpcTarget, "", dc.uuid)
195+
return dc
196+
}
197+
198+
// updateRLSServerTarget updates the RLS Server Target the RLS Balancer is
199+
// configured with.
200+
func (dc *dataCache) updateRLSServerTarget(rlsServerTarget string) {
201+
dc.rlsServerTarget = rlsServerTarget
182202
}
183203

184204
// resize changes the maximum allowed size of the data cache.
@@ -310,6 +330,9 @@ func (dc *dataCache) addEntry(key cacheKey, entry *cacheEntry) (backoffCancelled
310330
if dc.currentSize > dc.maxSize {
311331
backoffCancelled = dc.resize(dc.maxSize)
312332
}
333+
334+
cacheSizeMetric.Record(dc.metricsRecorder, dc.currentSize, dc.grpcTarget, dc.rlsServerTarget, dc.uuid)
335+
cacheEntriesMetric.Record(dc.metricsRecorder, int64(len(dc.entries)), dc.grpcTarget, dc.rlsServerTarget, dc.uuid)
313336
return backoffCancelled, true
314337
}
315338

@@ -319,6 +342,7 @@ func (dc *dataCache) updateEntrySize(entry *cacheEntry, newSize int64) {
319342
dc.currentSize -= entry.size
320343
entry.size = newSize
321344
dc.currentSize += entry.size
345+
cacheSizeMetric.Record(dc.metricsRecorder, dc.currentSize, dc.grpcTarget, dc.rlsServerTarget, dc.uuid)
322346
}
323347

324348
func (dc *dataCache) getEntry(key cacheKey) *cacheEntry {
@@ -351,6 +375,8 @@ func (dc *dataCache) deleteAndcleanup(key cacheKey, entry *cacheEntry) {
351375
delete(dc.entries, key)
352376
dc.currentSize -= entry.size
353377
dc.keys.removeEntry(key)
378+
cacheSizeMetric.Record(dc.metricsRecorder, dc.currentSize, dc.grpcTarget, dc.rlsServerTarget, dc.uuid)
379+
cacheEntriesMetric.Record(dc.metricsRecorder, int64(len(dc.entries)), dc.grpcTarget, dc.rlsServerTarget, dc.uuid)
354380
}
355381

356382
func (dc *dataCache) stop() {

balancer/rls/cache_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package rls
2020

2121
import (
22+
"google.golang.org/grpc/internal/testutils/stats"
2223
"testing"
2324
"time"
2425

@@ -119,7 +120,7 @@ func (s) TestLRU_BasicOperations(t *testing.T) {
119120

120121
func (s) TestDataCache_BasicOperations(t *testing.T) {
121122
initCacheEntries()
122-
dc := newDataCache(5, nil)
123+
dc := newDataCache(5, nil, &stats.NoopMetricsRecorder{}, "")
123124
for i, k := range cacheKeys {
124125
dc.addEntry(k, cacheEntries[i])
125126
}
@@ -133,7 +134,7 @@ func (s) TestDataCache_BasicOperations(t *testing.T) {
133134

134135
func (s) TestDataCache_AddForcesResize(t *testing.T) {
135136
initCacheEntries()
136-
dc := newDataCache(1, nil)
137+
dc := newDataCache(1, nil, &stats.NoopMetricsRecorder{}, "")
137138

138139
// The first entry in cacheEntries has a minimum expiry time in the future.
139140
// This entry would stop the resize operation since we do not evict entries
@@ -162,7 +163,7 @@ func (s) TestDataCache_AddForcesResize(t *testing.T) {
162163

163164
func (s) TestDataCache_Resize(t *testing.T) {
164165
initCacheEntries()
165-
dc := newDataCache(5, nil)
166+
dc := newDataCache(5, nil, &stats.NoopMetricsRecorder{}, "")
166167
for i, k := range cacheKeys {
167168
dc.addEntry(k, cacheEntries[i])
168169
}
@@ -193,7 +194,7 @@ func (s) TestDataCache_Resize(t *testing.T) {
193194

194195
func (s) TestDataCache_EvictExpiredEntries(t *testing.T) {
195196
initCacheEntries()
196-
dc := newDataCache(5, nil)
197+
dc := newDataCache(5, nil, &stats.NoopMetricsRecorder{}, "")
197198
for i, k := range cacheKeys {
198199
dc.addEntry(k, cacheEntries[i])
199200
}
@@ -220,7 +221,7 @@ func (s) TestDataCache_ResetBackoffState(t *testing.T) {
220221
}
221222

222223
initCacheEntries()
223-
dc := newDataCache(5, nil)
224+
dc := newDataCache(5, nil, &stats.NoopMetricsRecorder{}, "")
224225
for i, k := range cacheKeys {
225226
dc.addEntry(k, cacheEntries[i])
226227
}

internal/testutils/stats/test_metrics_recorder.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,19 @@ func (r *TestMetricsRecorder) TagConn(ctx context.Context, _ *stats.ConnTagInfo)
180180
}
181181

182182
func (r *TestMetricsRecorder) HandleConn(context.Context, stats.ConnStats) {}
183+
184+
// NoopMetricsRecorder is a noop MetricsRecorder to be used in tests to prevent
185+
// nil panics.
186+
type NoopMetricsRecorder struct{}
187+
188+
func (r *NoopMetricsRecorder) RecordInt64Count(_ *estats.Int64CountHandle, _ int64, _ ...string) {}
189+
190+
func (r *NoopMetricsRecorder) RecordFloat64Count(_ *estats.Float64CountHandle, _ float64, _ ...string) {
191+
}
192+
193+
func (r *NoopMetricsRecorder) RecordInt64Histo(_ *estats.Int64HistoHandle, _ int64, _ ...string) {}
194+
195+
func (r *NoopMetricsRecorder) RecordFloat64Histo(_ *estats.Float64HistoHandle, _ float64, _ ...string) {
196+
}
197+
198+
func (r *NoopMetricsRecorder) RecordInt64Gauge(_ *estats.Int64GaugeHandle, _ int64, _ ...string) {}

0 commit comments

Comments
 (0)