prometheus

Форк
0
/
bench_test.go 
433 строки · 10.9 Кб
1
// Copyright 2015 The Prometheus Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package promql_test
15

16
import (
17
	"context"
18
	"fmt"
19
	"strconv"
20
	"strings"
21
	"testing"
22
	"time"
23

24
	"github.com/prometheus/prometheus/model/histogram"
25
	"github.com/prometheus/prometheus/model/labels"
26
	"github.com/prometheus/prometheus/promql"
27
	"github.com/prometheus/prometheus/promql/parser"
28
	"github.com/prometheus/prometheus/storage"
29
	"github.com/prometheus/prometheus/tsdb/tsdbutil"
30
	"github.com/prometheus/prometheus/util/teststorage"
31
)
32

33
func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *promql.Engine, interval, numIntervals int) error {
34
	ctx := context.Background()
35

36
	metrics := []labels.Labels{}
37
	// Generating test series: a_X, b_X, and h_X, where X can take values of one, ten, or hundred,
38
	// representing the number of series each metric name contains.
39
	// Metric a_X and b_X are simple metrics where h_X is a histogram.
40
	// These metrics will have data for all test time range
41
	metrics = append(metrics, labels.FromStrings("__name__", "a_one"))
42
	metrics = append(metrics, labels.FromStrings("__name__", "b_one"))
43
	for j := 0; j < 10; j++ {
44
		metrics = append(metrics, labels.FromStrings("__name__", "h_one", "le", strconv.Itoa(j)))
45
	}
46
	metrics = append(metrics, labels.FromStrings("__name__", "h_one", "le", "+Inf"))
47

48
	for i := 0; i < 10; i++ {
49
		metrics = append(metrics, labels.FromStrings("__name__", "a_ten", "l", strconv.Itoa(i)))
50
		metrics = append(metrics, labels.FromStrings("__name__", "b_ten", "l", strconv.Itoa(i)))
51
		for j := 0; j < 10; j++ {
52
			metrics = append(metrics, labels.FromStrings("__name__", "h_ten", "l", strconv.Itoa(i), "le", strconv.Itoa(j)))
53
		}
54
		metrics = append(metrics, labels.FromStrings("__name__", "h_ten", "l", strconv.Itoa(i), "le", "+Inf"))
55
	}
56

57
	for i := 0; i < 100; i++ {
58
		metrics = append(metrics, labels.FromStrings("__name__", "a_hundred", "l", strconv.Itoa(i)))
59
		metrics = append(metrics, labels.FromStrings("__name__", "b_hundred", "l", strconv.Itoa(i)))
60
		for j := 0; j < 10; j++ {
61
			metrics = append(metrics, labels.FromStrings("__name__", "h_hundred", "l", strconv.Itoa(i), "le", strconv.Itoa(j)))
62
		}
63
		metrics = append(metrics, labels.FromStrings("__name__", "h_hundred", "l", strconv.Itoa(i), "le", "+Inf"))
64
	}
65
	refs := make([]storage.SeriesRef, len(metrics))
66

67
	// Number points for each different label value of "l" for the sparse series
68
	pointsPerSparseSeries := numIntervals / 50
69

70
	for s := 0; s < numIntervals; s++ {
71
		a := stor.Appender(context.Background())
72
		ts := int64(s * interval)
73
		for i, metric := range metrics {
74
			ref, _ := a.Append(refs[i], metric, ts, float64(s)+float64(i)/float64(len(metrics)))
75
			refs[i] = ref
76
		}
77
		// Generating a sparse time series: each label value of "l" will contain data only for
78
		// pointsPerSparseSeries points
79
		metric := labels.FromStrings("__name__", "sparse", "l", strconv.Itoa(s/pointsPerSparseSeries))
80
		_, err := a.Append(0, metric, ts, float64(s)/float64(len(metrics)))
81
		if err != nil {
82
			return err
83
		}
84
		if err := a.Commit(); err != nil {
85
			return err
86
		}
87
	}
88

89
	stor.DB.ForceHeadMMap() // Ensure we have at most one head chunk for every series.
90
	stor.DB.Compact(ctx)
91
	return nil
92
}
93

94
type benchCase struct {
95
	expr  string
96
	steps int
97
}
98

99
func rangeQueryCases() []benchCase {
100
	cases := []benchCase{
101
		// Plain retrieval.
102
		{
103
			expr: "a_X",
104
		},
105
		// Simple rate.
106
		{
107
			expr: "rate(a_X[1m])",
108
		},
109
		{
110
			expr:  "rate(a_X[1m])",
111
			steps: 10000,
112
		},
113
		{
114
			expr:  "rate(sparse[1m])",
115
			steps: 10000,
116
		},
117
		// Holt-Winters and long ranges.
118
		{
119
			expr: "holt_winters(a_X[1d], 0.3, 0.3)",
120
		},
121
		{
122
			expr: "changes(a_X[1d])",
123
		},
124
		{
125
			expr: "rate(a_X[1d])",
126
		},
127
		{
128
			expr: "absent_over_time(a_X[1d])",
129
		},
130
		// Unary operators.
131
		{
132
			expr: "-a_X",
133
		},
134
		// Binary operators.
135
		{
136
			expr: "a_X - b_X",
137
		},
138
		{
139
			expr:  "a_X - b_X",
140
			steps: 10000,
141
		},
142
		{
143
			expr: "a_X and b_X{l=~'.*[0-4]$'}",
144
		},
145
		{
146
			expr: "a_X or b_X{l=~'.*[0-4]$'}",
147
		},
148
		{
149
			expr: "a_X unless b_X{l=~'.*[0-4]$'}",
150
		},
151
		{
152
			expr: "a_X and b_X{l='notfound'}",
153
		},
154
		// Simple functions.
155
		{
156
			expr: "abs(a_X)",
157
		},
158
		{
159
			expr: "label_replace(a_X, 'l2', '$1', 'l', '(.*)')",
160
		},
161
		{
162
			expr: "label_join(a_X, 'l2', '-', 'l', 'l')",
163
		},
164
		// Simple aggregations.
165
		{
166
			expr: "sum(a_X)",
167
		},
168
		{
169
			expr: "sum without (l)(h_X)",
170
		},
171
		{
172
			expr: "sum without (le)(h_X)",
173
		},
174
		{
175
			expr: "sum by (l)(h_X)",
176
		},
177
		{
178
			expr: "sum by (le)(h_X)",
179
		},
180
		{
181
			expr:  "count_values('value', h_X)",
182
			steps: 100,
183
		},
184
		{
185
			expr: "topk(1, a_X)",
186
		},
187
		{
188
			expr: "topk(5, a_X)",
189
		},
190
		// Combinations.
191
		{
192
			expr: "rate(a_X[1m]) + rate(b_X[1m])",
193
		},
194
		{
195
			expr: "sum without (l)(rate(a_X[1m]))",
196
		},
197
		{
198
			expr: "sum without (l)(rate(a_X[1m])) / sum without (l)(rate(b_X[1m]))",
199
		},
200
		{
201
			expr: "histogram_quantile(0.9, rate(h_X[5m]))",
202
		},
203
		// Many-to-one join.
204
		{
205
			expr: "a_X + on(l) group_right a_one",
206
		},
207
		// Label compared to blank string.
208
		{
209
			expr:  "count({__name__!=\"\"})",
210
			steps: 1,
211
		},
212
		{
213
			expr:  "count({__name__!=\"\",l=\"\"})",
214
			steps: 1,
215
		},
216
		// Functions which have special handling inside eval()
217
		{
218
			expr: "timestamp(a_X)",
219
		},
220
	}
221

222
	// X in an expr will be replaced by different metric sizes.
223
	tmp := []benchCase{}
224
	for _, c := range cases {
225
		if !strings.Contains(c.expr, "X") {
226
			tmp = append(tmp, c)
227
		} else {
228
			tmp = append(tmp, benchCase{expr: strings.ReplaceAll(c.expr, "X", "one"), steps: c.steps})
229
			tmp = append(tmp, benchCase{expr: strings.ReplaceAll(c.expr, "X", "ten"), steps: c.steps})
230
			tmp = append(tmp, benchCase{expr: strings.ReplaceAll(c.expr, "X", "hundred"), steps: c.steps})
231
		}
232
	}
233
	cases = tmp
234

235
	// No step will be replaced by cases with the standard step.
236
	tmp = []benchCase{}
237
	for _, c := range cases {
238
		if c.steps != 0 {
239
			tmp = append(tmp, c)
240
		} else {
241
			tmp = append(tmp, benchCase{expr: c.expr, steps: 1})
242
			tmp = append(tmp, benchCase{expr: c.expr, steps: 100})
243
			tmp = append(tmp, benchCase{expr: c.expr, steps: 1000})
244
		}
245
	}
246
	return tmp
247
}
248

249
func BenchmarkRangeQuery(b *testing.B) {
250
	stor := teststorage.New(b)
251
	stor.DB.DisableCompactions() // Don't want auto-compaction disrupting timings.
252
	defer stor.Close()
253
	opts := promql.EngineOpts{
254
		Logger:     nil,
255
		Reg:        nil,
256
		MaxSamples: 50000000,
257
		Timeout:    100 * time.Second,
258
	}
259
	engine := promql.NewEngine(opts)
260

261
	const interval = 10000 // 10s interval.
262
	// A day of data plus 10k steps.
263
	numIntervals := 8640 + 10000
264

265
	err := setupRangeQueryTestData(stor, engine, interval, numIntervals)
266
	if err != nil {
267
		b.Fatal(err)
268
	}
269
	cases := rangeQueryCases()
270

271
	for _, c := range cases {
272
		name := fmt.Sprintf("expr=%s,steps=%d", c.expr, c.steps)
273
		b.Run(name, func(b *testing.B) {
274
			ctx := context.Background()
275
			b.ReportAllocs()
276
			for i := 0; i < b.N; i++ {
277
				qry, err := engine.NewRangeQuery(
278
					ctx, stor, nil, c.expr,
279
					time.Unix(int64((numIntervals-c.steps)*10), 0),
280
					time.Unix(int64(numIntervals*10), 0), time.Second*10)
281
				if err != nil {
282
					b.Fatal(err)
283
				}
284
				res := qry.Exec(ctx)
285
				if res.Err != nil {
286
					b.Fatal(res.Err)
287
				}
288
				qry.Close()
289
			}
290
		})
291
	}
292
}
293

294
func BenchmarkNativeHistograms(b *testing.B) {
295
	testStorage := teststorage.New(b)
296
	defer testStorage.Close()
297

298
	app := testStorage.Appender(context.TODO())
299
	if err := generateNativeHistogramSeries(app, 3000); err != nil {
300
		b.Fatal(err)
301
	}
302
	if err := app.Commit(); err != nil {
303
		b.Fatal(err)
304
	}
305

306
	start := time.Unix(0, 0)
307
	end := start.Add(2 * time.Hour)
308
	step := time.Second * 30
309

310
	cases := []struct {
311
		name  string
312
		query string
313
	}{
314
		{
315
			name:  "sum",
316
			query: "sum(native_histogram_series)",
317
		},
318
		{
319
			name:  "sum rate with short rate interval",
320
			query: "sum(rate(native_histogram_series[2m]))",
321
		},
322
		{
323
			name:  "sum rate with long rate interval",
324
			query: "sum(rate(native_histogram_series[20m]))",
325
		},
326
	}
327

328
	opts := promql.EngineOpts{
329
		Logger:               nil,
330
		Reg:                  nil,
331
		MaxSamples:           50000000,
332
		Timeout:              100 * time.Second,
333
		EnableAtModifier:     true,
334
		EnableNegativeOffset: true,
335
	}
336

337
	b.ResetTimer()
338
	b.ReportAllocs()
339

340
	for _, tc := range cases {
341
		b.Run(tc.name, func(b *testing.B) {
342
			ng := promql.NewEngine(opts)
343
			for i := 0; i < b.N; i++ {
344
				qry, err := ng.NewRangeQuery(context.Background(), testStorage, nil, tc.query, start, end, step)
345
				if err != nil {
346
					b.Fatal(err)
347
				}
348
				if result := qry.Exec(context.Background()); result.Err != nil {
349
					b.Fatal(result.Err)
350
				}
351
			}
352
		})
353
	}
354
}
355

356
func generateNativeHistogramSeries(app storage.Appender, numSeries int) error {
357
	commonLabels := []string{labels.MetricName, "native_histogram_series", "foo", "bar"}
358
	series := make([][]*histogram.Histogram, numSeries)
359
	for i := range series {
360
		series[i] = tsdbutil.GenerateTestHistograms(2000)
361
	}
362
	higherSchemaHist := &histogram.Histogram{
363
		Schema: 3,
364
		PositiveSpans: []histogram.Span{
365
			{Offset: -5, Length: 2}, // -5 -4
366
			{Offset: 2, Length: 3},  // -1 0 1
367
			{Offset: 2, Length: 2},  // 4 5
368
		},
369
		PositiveBuckets: []int64{1, 2, -2, 1, -1, 0, 3},
370
		Count:           13,
371
	}
372
	for sid, histograms := range series {
373
		seriesLabels := labels.FromStrings(append(commonLabels, "h", strconv.Itoa(sid))...)
374
		for i := range histograms {
375
			ts := time.Unix(int64(i*15), 0).UnixMilli()
376
			if i == 0 {
377
				// Inject a histogram with a higher schema.
378
				if _, err := app.AppendHistogram(0, seriesLabels, ts, higherSchemaHist, nil); err != nil {
379
					return err
380
				}
381
			}
382
			if _, err := app.AppendHistogram(0, seriesLabels, ts, histograms[i], nil); err != nil {
383
				return err
384
			}
385
		}
386
	}
387

388
	return nil
389
}
390

391
func BenchmarkParser(b *testing.B) {
392
	cases := []string{
393
		"a",
394
		"metric",
395
		"1",
396
		"1 >= bool 1",
397
		"1 + 2/(3*1)",
398
		"foo or bar",
399
		"foo and bar unless baz or qux",
400
		"bar + on(foo) bla / on(baz, buz) group_right(test) blub",
401
		"foo / ignoring(test,blub) group_left(blub) bar",
402
		"foo - ignoring(test,blub) group_right(bar,foo) bar",
403
		`foo{a="b", foo!="bar", test=~"test", bar!~"baz"}`,
404
		`min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]`,
405
		"sum without(and, by, avg, count, alert, annotations)(some_metric) [30m:10s]",
406
	}
407
	errCases := []string{
408
		"(",
409
		"}",
410
		"1 or 1",
411
		"1 or on(bar) foo",
412
		"foo unless on(bar) group_left(baz) bar",
413
		"test[5d] OFFSET 10s [10m:5s]",
414
	}
415

416
	for _, c := range cases {
417
		b.Run(c, func(b *testing.B) {
418
			b.ReportAllocs()
419
			for i := 0; i < b.N; i++ {
420
				parser.ParseExpr(c)
421
			}
422
		})
423
	}
424
	for _, c := range errCases {
425
		name := fmt.Sprintf("%s (should fail)", c)
426
		b.Run(name, func(b *testing.B) {
427
			b.ReportAllocs()
428
			for i := 0; i < b.N; i++ {
429
				parser.ParseExpr(c)
430
			}
431
		})
432
	}
433
}
434

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.