Skip to content

Commit d9764fb

Browse files
yeya24bwplotka
authored andcommitted
Added no-chunk option in series API (#1904)
Signed-off-by: yeya24 <yb532204897@gmail.com> add e2e tests Signed-off-by: yeya24 <yb532204897@gmail.com> add tests for all stores Signed-off-by: yeya24 <yb532204897@gmail.com> add changelog Signed-off-by: yeya24 <yb532204897@gmail.com>
1 parent bb346c0 commit d9764fb

File tree

18 files changed

+664
-245
lines changed

18 files changed

+664
-245
lines changed

.dep-finished

Whitespace-only changes.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ We use *breaking* word for marking changes that are not backward compatible (rel
2323
- [#1838](https://github.com/thanos-io/thanos/pull/1838) Ruler: Add TLS and authentication support for Alertmanager with the `--alertmanagers.config` and `--alertmanagers.config-file` CLI flags. See [documentation](docs/components/rule.md/#configuration) for further information.
2424
- [#1838](https://github.com/thanos-io/thanos/pull/1838) Ruler: Add a new `--alertmanagers.sd-dns-interval` CLI option to specify the interval between DNS resolutions of Alertmanager hosts.
2525
- [#1881](https://github.com/thanos-io/thanos/pull/1881) Store Gateway: memcached support for index cache. See [documentation](docs/components/store.md/#index-cache) for further information.
26+
- [#1904](https://github.com/thanos-io/thanos/pull/1904) Add a skip-chunks option in Store Series API to improve the response time of `/api/v1/series` endpoint.
2627

2728
## [v0.9.0](https://github.com/thanos-io/thanos/releases/tag/v0.9.0) - 2019.12.03
2829

pkg/query/api/v1.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ func (api *API) query(r *http.Request) (interface{}, []error, *ApiError) {
293293
span, ctx := tracing.StartSpan(ctx, "promql_instant_query")
294294
defer span.Finish()
295295

296-
qry, err := api.queryEngine.NewInstantQuery(api.queryableCreate(enableDedup, replicaLabels, maxSourceResolution, enablePartialResponse), r.FormValue("query"), ts)
296+
qry, err := api.queryEngine.NewInstantQuery(api.queryableCreate(enableDedup, replicaLabels, maxSourceResolution, enablePartialResponse, false), r.FormValue("query"), ts)
297297
if err != nil {
298298
return nil, nil, &ApiError{errorBadData, err}
299299
}
@@ -386,7 +386,7 @@ func (api *API) queryRange(r *http.Request) (interface{}, []error, *ApiError) {
386386
defer span.Finish()
387387

388388
qry, err := api.queryEngine.NewRangeQuery(
389-
api.queryableCreate(enableDedup, replicaLabels, maxSourceResolution, enablePartialResponse),
389+
api.queryableCreate(enableDedup, replicaLabels, maxSourceResolution, enablePartialResponse, false),
390390
r.FormValue("query"),
391391
start,
392392
end,
@@ -426,7 +426,7 @@ func (api *API) labelValues(r *http.Request) (interface{}, []error, *ApiError) {
426426
return nil, nil, apiErr
427427
}
428428

429-
q, err := api.queryableCreate(true, nil, 0, enablePartialResponse).Querier(ctx, math.MinInt64, math.MaxInt64)
429+
q, err := api.queryableCreate(true, nil, 0, enablePartialResponse, false).Querier(ctx, math.MinInt64, math.MaxInt64)
430430
if err != nil {
431431
return nil, nil, &ApiError{errorExec, err}
432432
}
@@ -503,7 +503,7 @@ func (api *API) series(r *http.Request) (interface{}, []error, *ApiError) {
503503
}
504504

505505
// TODO(bwplotka): Support downsampling?
506-
q, err := api.queryableCreate(enableDedup, replicaLabels, 0, enablePartialResponse).
506+
q, err := api.queryableCreate(enableDedup, replicaLabels, 0, enablePartialResponse, true).
507507
Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
508508
if err != nil {
509509
return nil, nil, &ApiError{errorExec, err}
@@ -607,7 +607,7 @@ func (api *API) labelNames(r *http.Request) (interface{}, []error, *ApiError) {
607607
return nil, nil, apiErr
608608
}
609609

610-
q, err := api.queryableCreate(true, nil, 0, enablePartialResponse).Querier(ctx, math.MinInt64, math.MaxInt64)
610+
q, err := api.queryableCreate(true, nil, 0, enablePartialResponse, false).Querier(ctx, math.MinInt64, math.MaxInt64)
611611
if err != nil {
612612
return nil, nil, &ApiError{errorExec, err}
613613
}

pkg/query/querier.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,19 @@ import (
1919
// replicaLabels at query time.
2020
// maxResolutionMillis controls downsampling resolution that is allowed (specified in milliseconds).
2121
// partialResponse controls `partialResponseDisabled` option of StoreAPI and partial response behaviour of proxy.
22-
type QueryableCreator func(deduplicate bool, replicaLabels []string, maxResolutionMillis int64, partialResponse bool) storage.Queryable
22+
type QueryableCreator func(deduplicate bool, replicaLabels []string, maxResolutionMillis int64, partialResponse, skipChunks bool) storage.Queryable
2323

2424
// NewQueryableCreator creates QueryableCreator.
2525
func NewQueryableCreator(logger log.Logger, proxy storepb.StoreServer) QueryableCreator {
26-
return func(deduplicate bool, replicaLabels []string, maxResolutionMillis int64, partialResponse bool) storage.Queryable {
26+
return func(deduplicate bool, replicaLabels []string, maxResolutionMillis int64, partialResponse, skipChunks bool) storage.Queryable {
2727
return &queryable{
2828
logger: logger,
2929
replicaLabels: replicaLabels,
3030
proxy: proxy,
3131
deduplicate: deduplicate,
3232
maxResolutionMillis: maxResolutionMillis,
3333
partialResponse: partialResponse,
34+
skipChunks: skipChunks,
3435
}
3536
}
3637
}
@@ -42,11 +43,12 @@ type queryable struct {
4243
deduplicate bool
4344
maxResolutionMillis int64
4445
partialResponse bool
46+
skipChunks bool
4547
}
4648

4749
// Querier returns a new storage querier against the underlying proxy store API.
4850
func (q *queryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
49-
return newQuerier(ctx, q.logger, mint, maxt, q.replicaLabels, q.proxy, q.deduplicate, int64(q.maxResolutionMillis), q.partialResponse), nil
51+
return newQuerier(ctx, q.logger, mint, maxt, q.replicaLabels, q.proxy, q.deduplicate, int64(q.maxResolutionMillis), q.partialResponse, q.skipChunks), nil
5052
}
5153

5254
type querier struct {
@@ -59,6 +61,7 @@ type querier struct {
5961
deduplicate bool
6062
maxResolutionMillis int64
6163
partialResponse bool
64+
skipChunks bool
6265
}
6366

6467
// newQuerier creates implementation of storage.Querier that fetches data from the proxy
@@ -72,6 +75,7 @@ func newQuerier(
7275
deduplicate bool,
7376
maxResolutionMillis int64,
7477
partialResponse bool,
78+
skipChunks bool,
7579
) *querier {
7680
if logger == nil {
7781
logger = log.NewNopLogger()
@@ -93,6 +97,7 @@ func newQuerier(
9397
deduplicate: deduplicate,
9498
maxResolutionMillis: maxResolutionMillis,
9599
partialResponse: partialResponse,
100+
skipChunks: skipChunks,
96101
}
97102
}
98103

@@ -185,6 +190,7 @@ func (q *querier) Select(params *storage.SelectParams, ms ...*labels.Matcher) (s
185190
MaxResolutionWindow: q.maxResolutionMillis,
186191
Aggregates: queryAggrs,
187192
PartialResponseDisabled: !q.partialResponse,
193+
SkipChunks: q.skipChunks,
188194
}, resp); err != nil {
189195
return nil, nil, errors.Wrap(err, "proxy Series()")
190196
}

pkg/query/querier_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestQueryableCreator_MaxResolution(t *testing.T) {
2828
queryableCreator := NewQueryableCreator(nil, testProxy)
2929

3030
oneHourMillis := int64(1*time.Hour) / int64(time.Millisecond)
31-
queryable := queryableCreator(false, nil, oneHourMillis, false)
31+
queryable := queryableCreator(false, nil, oneHourMillis, false, false)
3232

3333
q, err := queryable.Querier(context.Background(), 0, 42)
3434
testutil.Ok(t, err)
@@ -55,7 +55,7 @@ func TestQuerier_DownsampledData(t *testing.T) {
5555
},
5656
}
5757

58-
q := NewQueryableCreator(nil, testProxy)(false, nil, 9999999, false)
58+
q := NewQueryableCreator(nil, testProxy)(false, nil, 9999999, false, false)
5959

6060
engine := promql.NewEngine(
6161
promql.EngineOpts{
@@ -176,7 +176,7 @@ func TestQuerier_Series(t *testing.T) {
176176

177177
// Querier clamps the range to [1,300], which should drop some samples of the result above.
178178
// The store API allows endpoints to send more data then initially requested.
179-
q := newQuerier(context.Background(), nil, 1, 300, []string{""}, testProxy, false, 0, true)
179+
q := newQuerier(context.Background(), nil, 1, 300, []string{""}, testProxy, false, 0, true, false)
180180
defer func() { testutil.Ok(t, q.Close()) }()
181181

182182
res, _, err := q.Select(&storage.SelectParams{})

pkg/store/bucket.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -946,11 +946,16 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, srv storepb.Store_Serie
946946
for set.Next() {
947947
var series storepb.Series
948948

949-
series.Labels, series.Chunks = set.At()
950-
951949
stats.mergedSeriesCount++
952-
stats.mergedChunksCount += len(series.Chunks)
953-
s.metrics.chunkSizeBytes.Observe(float64(chunksSize(series.Chunks)))
950+
951+
if req.SkipChunks {
952+
series.Labels, _ = set.At()
953+
} else {
954+
series.Labels, series.Chunks = set.At()
955+
956+
stats.mergedChunksCount += len(series.Chunks)
957+
s.metrics.chunkSizeBytes.Observe(float64(chunksSize(series.Chunks)))
958+
}
954959

955960
if err := srv.Send(storepb.NewSeriesResponse(&series)); err != nil {
956961
return status.Error(codes.Unknown, errors.Wrap(err, "send series response").Error())

pkg/store/bucket_e2e_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
173173

174174
// TODO(bwplotka): Add those test cases to TSDB querier_test.go as well, there are no tests for matching.
175175
for i, tcase := range []struct {
176-
req *storepb.SeriesRequest
177-
expected [][]storepb.Label
176+
req *storepb.SeriesRequest
177+
expected [][]storepb.Label
178+
expectedChunkLen int
178179
}{
179180
{
180181
req: &storepb.SeriesRequest{
@@ -184,6 +185,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
184185
MinTime: mint,
185186
MaxTime: maxt,
186187
},
188+
expectedChunkLen: 3,
187189
expected: [][]storepb.Label{
188190
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
189191
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -203,6 +205,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
203205
MinTime: mint,
204206
MaxTime: maxt,
205207
},
208+
expectedChunkLen: 3,
206209
expected: [][]storepb.Label{
207210
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
208211
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -218,6 +221,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
218221
MinTime: mint,
219222
MaxTime: maxt,
220223
},
224+
expectedChunkLen: 3,
221225
expected: [][]storepb.Label{
222226
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
223227
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -233,6 +237,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
233237
MinTime: mint,
234238
MaxTime: maxt,
235239
},
240+
expectedChunkLen: 3,
236241
expected: [][]storepb.Label{
237242
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
238243
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -252,6 +257,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
252257
MinTime: mint,
253258
MaxTime: maxt,
254259
},
260+
expectedChunkLen: 3,
255261
expected: [][]storepb.Label{
256262
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
257263
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -271,6 +277,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
271277
MinTime: mint,
272278
MaxTime: maxt,
273279
},
280+
expectedChunkLen: 3,
274281
expected: [][]storepb.Label{
275282
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
276283
{{Name: "a", Value: "2"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -286,6 +293,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
286293
MinTime: mint,
287294
MaxTime: maxt,
288295
},
296+
expectedChunkLen: 3,
289297
expected: [][]storepb.Label{
290298
{{Name: "a", Value: "1"}, {Name: "c", Value: "1"}, {Name: "ext2", Value: "value2"}},
291299
{{Name: "a", Value: "1"}, {Name: "c", Value: "2"}, {Name: "ext2", Value: "value2"}},
@@ -309,6 +317,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
309317
MinTime: mint,
310318
MaxTime: maxt,
311319
},
320+
expectedChunkLen: 3,
312321
expected: [][]storepb.Label{
313322
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
314323
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -324,6 +333,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
324333
MinTime: mint,
325334
MaxTime: maxt,
326335
},
336+
expectedChunkLen: 3,
327337
expected: [][]storepb.Label{
328338
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
329339
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
@@ -347,6 +357,24 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
347357
MaxTime: maxt,
348358
},
349359
},
360+
// Test no-chunk option.
361+
{
362+
req: &storepb.SeriesRequest{
363+
Matchers: []storepb.LabelMatcher{
364+
{Type: storepb.LabelMatcher_EQ, Name: "a", Value: "1"},
365+
},
366+
MinTime: mint,
367+
MaxTime: maxt,
368+
SkipChunks: true,
369+
},
370+
expectedChunkLen: 0,
371+
expected: [][]storepb.Label{
372+
{{Name: "a", Value: "1"}, {Name: "b", Value: "1"}, {Name: "ext1", Value: "value1"}},
373+
{{Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "ext1", Value: "value1"}},
374+
{{Name: "a", Value: "1"}, {Name: "c", Value: "1"}, {Name: "ext2", Value: "value2"}},
375+
{{Name: "a", Value: "1"}, {Name: "c", Value: "2"}, {Name: "ext2", Value: "value2"}},
376+
},
377+
},
350378
} {
351379
t.Log("Run ", i)
352380

@@ -357,7 +385,7 @@ func testBucketStore_e2e(t testing.TB, ctx context.Context, s *storeSuite) {
357385

358386
for i, s := range srv.SeriesSet {
359387
testutil.Equals(t, tcase.expected[i], s.Labels)
360-
testutil.Equals(t, 3, len(s.Chunks))
388+
testutil.Equals(t, tcase.expectedChunkLen, len(s.Chunks))
361389
}
362390
}
363391
}

pkg/store/matchers.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,21 @@ func translateMatchers(ms []storepb.LabelMatcher) (res []*labels.Matcher, err er
3333
}
3434
return res, nil
3535
}
36+
37+
// matchersToString converts label matchers to string format.
38+
func matchersToString(ms []storepb.LabelMatcher) (string, error) {
39+
var res string
40+
matchers, err := translateMatchers(ms)
41+
if err != nil {
42+
return "", err
43+
}
44+
45+
for i, m := range matchers {
46+
res += m.String()
47+
if i < len(matchers)-1 {
48+
res += ", "
49+
}
50+
}
51+
52+
return "{" + res + "}", nil
53+
}

pkg/store/matchers_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package store
2+
3+
import (
4+
"testing"
5+
6+
"github.com/thanos-io/thanos/pkg/store/storepb"
7+
"github.com/thanos-io/thanos/pkg/testutil"
8+
)
9+
10+
func TestMatchersToString(t *testing.T) {
11+
cases := []struct {
12+
ms []storepb.LabelMatcher
13+
expected string
14+
}{
15+
{
16+
ms: []storepb.LabelMatcher{
17+
{
18+
Name: "__name__",
19+
Type: storepb.LabelMatcher_EQ,
20+
Value: "up",
21+
}},
22+
expected: `{__name__="up"}`,
23+
},
24+
{
25+
ms: []storepb.LabelMatcher{
26+
{
27+
Name: "__name__",
28+
Type: storepb.LabelMatcher_NEQ,
29+
Value: "up",
30+
},
31+
{
32+
Name: "job",
33+
Type: storepb.LabelMatcher_EQ,
34+
Value: "test",
35+
},
36+
},
37+
expected: `{__name__!="up", job="test"}`,
38+
},
39+
{
40+
ms: []storepb.LabelMatcher{
41+
{
42+
Name: "__name__",
43+
Type: storepb.LabelMatcher_EQ,
44+
Value: "up",
45+
},
46+
{
47+
Name: "job",
48+
Type: storepb.LabelMatcher_RE,
49+
Value: "test",
50+
},
51+
},
52+
expected: `{__name__="up", job=~"test"}`,
53+
},
54+
{
55+
ms: []storepb.LabelMatcher{
56+
{
57+
Name: "job",
58+
Type: storepb.LabelMatcher_NRE,
59+
Value: "test",
60+
}},
61+
expected: `{job!~"test"}`,
62+
},
63+
{
64+
ms: []storepb.LabelMatcher{
65+
{
66+
Name: "__name__",
67+
Type: storepb.LabelMatcher_EQ,
68+
Value: "up",
69+
},
70+
{
71+
Name: "__name__",
72+
Type: storepb.LabelMatcher_NEQ,
73+
Value: "up",
74+
},
75+
},
76+
// We cannot use up{__name__!="up"} in this case.
77+
expected: `{__name__="up", __name__!="up"}`,
78+
},
79+
}
80+
81+
for i, c := range cases {
82+
actual, err := matchersToString(c.ms)
83+
testutil.Ok(t, err)
84+
testutil.Assert(t, actual == c.expected, "test case %d failed, expected %s, actual %s", i, c.expected, actual)
85+
}
86+
}

0 commit comments

Comments
 (0)