Skip to content

Commit 9201951

Browse files
committed
collector: cache only counters
Use cache to interpolate values when counters reset, as with statement statistics from internal tables. Gauges do not need caching, so this change disables it for gauges.
1 parent 77e084b commit 9201951

File tree

2 files changed

+65
-64
lines changed

2 files changed

+65
-64
lines changed

internal/collector/collector.go

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,25 @@ type Collector interface {
5555

5656
// collector implementation. To reduce the cardinality of the metrics, it keeps a cache
5757
// of metrics
58+
// TODO(silvano): refactor to use a more efficient data structure. Many of these
59+
// members could be retrieved from the *store.Collection.
5860
type collector struct {
59-
name string
60-
lastModified time.Time
61-
cardinality int
62-
enabled bool
63-
frequency int
64-
labels []string
65-
labelMap map[string]int
66-
metrics map[string]metric
67-
databases string
68-
query string
69-
first bool
70-
metricsCache *lru.Cache
71-
gauges map[string]map[string][]string
72-
maxResults int
73-
registerer prometheus.Registerer
74-
mu struct {
61+
name string
62+
countersCache *lru.Cache
63+
countersCardinality int
64+
databases string
65+
enabled bool
66+
first bool
67+
frequency int
68+
gaugeLabels map[string]map[string][]string
69+
labelMap map[string]int
70+
labels []string
71+
lastModified time.Time
72+
maxResults int
73+
metrics map[string]metric
74+
query string
75+
registerer prometheus.Registerer
76+
mu struct {
7577
sync.Mutex
7678
inUse bool
7779
}
@@ -153,7 +155,7 @@ func FromCollection(coll *store.Collection, registerer prometheus.Registerer) (C
153155

154156
// AddCounter adds a metric counter. The name must match one of the columns returned by the query.
155157
func (c *collector) AddCounter(name string, help string) error {
156-
c.cardinality++
158+
c.countersCardinality++
157159
metricName := c.name + "_" + name
158160
vec := prometheus.NewCounterVec(
159161
prometheus.CounterOpts{
@@ -179,7 +181,6 @@ func (c *collector) AddCounter(name string, help string) error {
179181

180182
// AddGauge adds a metric gauge. The name must match one of the columns returned by the query.
181183
func (c *collector) AddGauge(name string, help string) error {
182-
c.cardinality++
183184
metricName := c.name + "_" + name
184185
vec := prometheus.NewGaugeVec(
185186
prometheus.GaugeOpts{
@@ -394,7 +395,7 @@ func (c *collector) counterAdd(
394395
return
395396
}
396397
var delta float64
397-
v, ok := c.metricsCache.Get(key)
398+
v, ok := c.countersCache.Get(key)
398399
if ok {
399400
cv, _ := v.(cacheValue)
400401
if cv.value > value {
@@ -406,19 +407,14 @@ func (c *collector) counterAdd(
406407
delta = value
407408
}
408409
vec.WithLabelValues(labels...).Add(delta)
409-
c.metricsCache.Add(key, cacheValue{labels, value, vec})
410+
c.countersCache.Add(key, cacheValue{labels, value, vec})
410411
}
411412

412413
// gaugeSet sets a gauge value.
413414
func (c *collector) gaugeSet(
414415
vec *prometheus.GaugeVec, name string, labels []string, value float64,
415416
) {
416-
key, err := c.getKey(name, labels)
417-
if err != nil {
418-
return
419-
}
420417
vec.WithLabelValues(labels...).Set(value)
421-
c.metricsCache.Add(key, cacheValue{labels, value, vec})
422418
}
423419

424420
func (c *collector) getAllLabels() []string {
@@ -444,23 +440,26 @@ func (c *collector) getKey(name string, labels []string) (string, error) {
444440
// clearObsoleteGauges removes the metrics for labels that are no longer present.
445441
// This is required to prevent obsolete metrics from being reported.
446442
func (c *collector) clearObsoleteGauges(currGauges map[string]map[string][]string) {
447-
for colName, labels := range c.gauges {
443+
for gaugeName, labels := range c.gaugeLabels {
448444
for id, lbs := range labels {
449-
if _, ok := currGauges[colName][id]; ok {
445+
if _, ok := currGauges[gaugeName][id]; ok {
446+
continue
447+
}
448+
metric, ok := c.metrics[gaugeName]
449+
if !ok {
450450
continue
451451
}
452-
metric := c.metrics[colName]
453452
vec := metric.vec.(*prometheus.GaugeVec)
454453
vec.DeleteLabelValues(lbs...)
455454
}
456455
}
457-
c.gauges = currGauges
456+
c.gaugeLabels = currGauges
458457
}
459458

460459
func (c *collector) maybeInitCache() {
461-
if c.metricsCache == nil {
462-
c.metricsCache = lru.New(c.cardinality * c.maxResults * 2)
463-
c.metricsCache.OnEvicted = func(key lru.Key, value interface{}) {
460+
if c.countersCache == nil {
461+
c.countersCache = lru.New(c.countersCardinality * c.maxResults * 2)
462+
c.countersCache.OnEvicted = func(key lru.Key, value interface{}) {
464463
labels := value.(cacheValue).labels
465464
vec := value.(cacheValue).vec
466465
vec.DeleteLabelValues(labels...)

internal/collector/collector_test.go

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,11 @@ func TestCollect(t *testing.T) {
155155
r.NoError(err)
156156
collector := coll.(*collector)
157157
collector.maybeInitCache()
158-
r.Equal(8, collector.metricsCache.MaxEntries)
159-
r.Equal(0, collector.metricsCache.Len())
158+
r.Equal(4, collector.countersCache.MaxEntries)
159+
r.Equal(0, collector.countersCache.Len())
160160
tests := []test{
161161
{
162-
"one",
162+
"start",
163163
[]sample{
164164
{"test1", 1, 1},
165165
{"test2", 1, 5},
@@ -168,10 +168,10 @@ func TestCollect(t *testing.T) {
168168
counterMetricName: {"label:test1 1.000000", "label:test2 1.000000"},
169169
gaugeMetricName: {"label:test1 1.000000", "label:test2 5.000000"},
170170
},
171-
4,
171+
2,
172172
},
173173
{
174-
"two",
174+
"counter_increase",
175175
[]sample{
176176
{"test1", 1, 3},
177177
{"test2", 1, 1},
@@ -180,10 +180,10 @@ func TestCollect(t *testing.T) {
180180
counterMetricName: {"label:test1 1.000000", "label:test2 1.000000"},
181181
gaugeMetricName: {"label:test1 3.000000", "label:test2 1.000000"},
182182
},
183-
4,
183+
2,
184184
},
185185
{
186-
"three",
186+
"counter_increase_again",
187187
[]sample{
188188
{"test1", 4, 1},
189189
{"test2", 2, 1},
@@ -192,10 +192,10 @@ func TestCollect(t *testing.T) {
192192
counterMetricName: {"label:test1 4.000000", "label:test2 2.000000"},
193193
gaugeMetricName: {"label:test1 1.000000", "label:test2 1.000000"},
194194
},
195-
4,
195+
2,
196196
},
197197
{
198-
"four_counter_reset",
198+
"counter_reset",
199199
[]sample{
200200
{"test1", 2, 1},
201201
{"test3", 2, 1},
@@ -204,10 +204,10 @@ func TestCollect(t *testing.T) {
204204
counterMetricName: {"label:test1 6.000000", "label:test2 2.000000", "label:test3 2.000000"},
205205
gaugeMetricName: {"label:test1 1.000000", "label:test3 1.000000"},
206206
},
207-
6,
207+
3,
208208
},
209209
{
210-
"five",
210+
"new_labels",
211211
[]sample{
212212
{"test1", 2, 1},
213213
{"test4", 2, 1},
@@ -216,10 +216,10 @@ func TestCollect(t *testing.T) {
216216
counterMetricName: {"label:test1 6.000000", "label:test2 2.000000", "label:test3 2.000000", "label:test4 2.000000"},
217217
gaugeMetricName: {"label:test1 1.000000", "label:test4 1.000000"},
218218
},
219-
8,
219+
4,
220220
},
221221
{
222-
"six_test2_evicted",
222+
"test2_evicted",
223223
[]sample{
224224
{"test1", 2, 1},
225225
{"test5", 2, 1},
@@ -228,9 +228,10 @@ func TestCollect(t *testing.T) {
228228
counterMetricName: {"label:test1 6.000000", "label:test3 2.000000", "label:test4 2.000000", "label:test5 2.000000"},
229229
gaugeMetricName: {"label:test1 1.000000", "label:test5 1.000000"},
230230
},
231-
8,
231+
4,
232232
},
233233
}
234+
// run sequentially only
234235
for _, tt := range tests {
235236
t.Run(tt.name, func(t *testing.T) {
236237
testCollect(t, collector, mock, tt.samples)
@@ -240,12 +241,12 @@ func TestCollect(t *testing.T) {
240241
expectedGaugeLabels[i] = s.label
241242
}
242243
var actualGaugeLabels []string
243-
for k := range collector.gauges[gauge] {
244+
for k := range collector.gaugeLabels[gauge] {
244245
actualGaugeLabels = append(actualGaugeLabels, k)
245246
}
246247
a.ElementsMatch(expectedGaugeLabels,
247248
actualGaugeLabels)
248-
a.Equal(tt.cacheLen, collector.metricsCache.Len())
249+
a.Equal(tt.cacheLen, collector.countersCache.Len())
249250
})
250251
}
251252
}
@@ -270,11 +271,11 @@ func TestDatabaseCollect(t *testing.T) {
270271
r.NoError(err)
271272
collector := coll.(*collector)
272273
collector.maybeInitCache()
273-
r.Equal(8, collector.metricsCache.MaxEntries)
274-
r.Equal(0, collector.metricsCache.Len())
274+
r.Equal(4, collector.countersCache.MaxEntries)
275+
r.Equal(0, collector.countersCache.Len())
275276
tests := []test{
276277
{
277-
"one",
278+
"start",
278279
[]sample{
279280
{"test1", 1, 1},
280281
{"test2", 1, 5},
@@ -283,10 +284,10 @@ func TestDatabaseCollect(t *testing.T) {
283284
counterMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test2 1.000000"},
284285
gaugeMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test2 5.000000"},
285286
},
286-
4,
287+
2,
287288
},
288289
{
289-
"two",
290+
"counter_increase",
290291
[]sample{
291292
{"test1", 1, 3},
292293
{"test2", 1, 1},
@@ -295,10 +296,10 @@ func TestDatabaseCollect(t *testing.T) {
295296
counterMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test2 1.000000"},
296297
gaugeMetricName: {"_database:mydb,label:test1 3.000000", "_database:mydb,label:test2 1.000000"},
297298
},
298-
4,
299+
2,
299300
},
300301
{
301-
"three",
302+
"counter_increase_again",
302303
[]sample{
303304
{"test1", 4, 1},
304305
{"test2", 2, 1},
@@ -307,10 +308,10 @@ func TestDatabaseCollect(t *testing.T) {
307308
counterMetricName: {"_database:mydb,label:test1 4.000000", "_database:mydb,label:test2 2.000000"},
308309
gaugeMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test2 1.000000"},
309310
},
310-
4,
311+
2,
311312
},
312313
{
313-
"four_counter_reset",
314+
"counter_reset",
314315
[]sample{
315316
{"test1", 2, 1},
316317
{"test3", 2, 1},
@@ -319,10 +320,10 @@ func TestDatabaseCollect(t *testing.T) {
319320
counterMetricName: {"_database:mydb,label:test1 6.000000", "_database:mydb,label:test2 2.000000", "_database:mydb,label:test3 2.000000"},
320321
gaugeMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test3 1.000000"},
321322
},
322-
6,
323+
3,
323324
},
324325
{
325-
"five",
326+
"new_labels",
326327
[]sample{
327328
{"test1", 2, 1},
328329
{"test4", 2, 1},
@@ -331,10 +332,10 @@ func TestDatabaseCollect(t *testing.T) {
331332
counterMetricName: {"_database:mydb,label:test1 6.000000", "_database:mydb,label:test2 2.000000", "_database:mydb,label:test3 2.000000", "_database:mydb,label:test4 2.000000"},
332333
gaugeMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test4 1.000000"},
333334
},
334-
8,
335+
4,
335336
},
336337
{
337-
"six_test2_evicted",
338+
"test2_evicted",
338339
[]sample{
339340
{"test1", 2, 1},
340341
{"test5", 2, 1},
@@ -343,20 +344,21 @@ func TestDatabaseCollect(t *testing.T) {
343344
counterMetricName: {"_database:mydb,label:test1 6.000000", "_database:mydb,label:test3 2.000000", "_database:mydb,label:test4 2.000000", "_database:mydb,label:test5 2.000000"},
344345
gaugeMetricName: {"_database:mydb,label:test1 1.000000", "_database:mydb,label:test5 1.000000"},
345346
},
346-
8,
347+
4,
347348
},
348349
}
350+
// run sequentially only
349351
for _, tt := range tests {
350352
t.Run(tt.name, func(t *testing.T) {
351353
testDatabaseCollect(t, collector, mock, tt.samples)
352354
testVerify(t, prefix, tt.expected)
353-
a.Equal(tt.cacheLen, collector.metricsCache.Len())
355+
a.Equal(tt.cacheLen, collector.countersCache.Len())
354356
expectedGaugeLabels := make([]string, len(tt.samples))
355357
for i, s := range tt.samples {
356358
expectedGaugeLabels[i] = fmt.Sprintf("%s|%s", s.label, dbName)
357359
}
358360
var actualGaugeLabels []string
359-
for k := range collector.gauges[gauge] {
361+
for k := range collector.gaugeLabels[gauge] {
360362
actualGaugeLabels = append(actualGaugeLabels, k)
361363
}
362364
a.ElementsMatch(expectedGaugeLabels, actualGaugeLabels)

0 commit comments

Comments
 (0)