Skip to content

Commit 85c3781

Browse files
edma2Eugene Ma
and
Eugene Ma
authored
Fix tenant federation performance hotspot (cortexproject#4502)
* merge queryable: cache curr series Signed-off-by: Eugene Ma <eugene.ma@airbnb.com> * add test to check label set Signed-off-by: Eugene Ma <eugene.ma@airbnb.com> * update CHANGELOG Signed-off-by: Eugene Ma <eugene.ma@airbnb.com> Co-authored-by: Eugene Ma <eugene.ma@airbnb.com>
1 parent 8487508 commit 85c3781

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
* [ENHANCEMENT] New options `-server.http-listen-network` and `-server.grpc-listen-network` allow binding as 'tcp4' or 'tcp6'. #4462
4949
* [ENHANCEMENT] Rulers: Using shuffle sharding subring on GetRules API. #4466
5050
* [ENHANCEMENT] Support memcached auto-discovery via `auto-discovery` flag, introduced by thanos in https://github.com/thanos-io/thanos/pull/4487. Both AWS and Google Cloud memcached service support auto-discovery, which returns a list of nodes of the memcached cluster. #4412
51+
* [ENHANCEMENT] Query federation: improve performance in MergeQueryable by memoizing labels. #4502
5152
* [BUGFIX] Fixes a panic in the query-tee when comparing result. #4465
5253
* [BUGFIX] Frontend: Fixes @ modifier functions (start/end) when splitting queries by time. #4464
5354
* [BUGFIX] Compactor: compactor will no longer try to compact blocks that are already marked for deletion. Previously compactor would consider blocks marked for deletion within `-compactor.deletion-delay / 2` period as eligible for compaction. #4328

pkg/querier/tenantfederation/merge_queryable.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,20 +387,26 @@ func filterValuesByMatchers(idLabelName string, ids []string, matchers ...*label
387387
}
388388

389389
type addLabelsSeriesSet struct {
390-
upstream storage.SeriesSet
391-
labels labels.Labels
390+
upstream storage.SeriesSet
391+
labels labels.Labels
392+
currSeries storage.Series
392393
}
393394

394395
func (m *addLabelsSeriesSet) Next() bool {
396+
m.currSeries = nil
395397
return m.upstream.Next()
396398
}
397399

398400
// At returns full series. Returned series should be iteratable even after Next is called.
399401
func (m *addLabelsSeriesSet) At() storage.Series {
400-
return &addLabelsSeries{
401-
upstream: m.upstream.At(),
402-
labels: m.labels,
402+
if m.currSeries == nil {
403+
upstream := m.upstream.At()
404+
m.currSeries = &addLabelsSeries{
405+
upstream: upstream,
406+
labels: setLabelsRetainExisting(upstream.Labels(), m.labels...),
407+
}
403408
}
409+
return m.currSeries
404410
}
405411

406412
// The error that iteration as failed with.
@@ -441,7 +447,7 @@ type addLabelsSeries struct {
441447

442448
// Labels returns the complete set of labels. For series it means all labels identifying the series.
443449
func (a *addLabelsSeries) Labels() labels.Labels {
444-
return setLabelsRetainExisting(a.upstream.Labels(), a.labels...)
450+
return a.labels
445451
}
446452

447453
// Iterator returns a new, independent iterator of the data of the series.

pkg/querier/tenantfederation/merge_queryable_test.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ type selectTestCase struct {
277277
matchers []*labels.Matcher
278278
// expectedSeriesCount is the expected number of series returned by a Select filtered by the Matchers in selector.
279279
expectedSeriesCount int
280+
// expectedLabels is the expected label sets returned by a Select filtered by the Matchers in selector.
281+
expectedLabels []labels.Labels
280282
// expectedWarnings is a slice of storage.Warnings messages expected when querying.
281283
expectedWarnings []string
282284
// expectedQueryErr is the error expected when querying.
@@ -425,6 +427,41 @@ func TestMergeQueryable_Select(t *testing.T) {
425427
{
426428
name: "should return all series when no matchers are provided",
427429
expectedSeriesCount: 6,
430+
expectedLabels: []labels.Labels{
431+
{
432+
{Name: "__tenant_id__", Value: "team-a"},
433+
{Name: "instance", Value: "host1"},
434+
{Name: "original___tenant_id__", Value: "original-value"},
435+
{Name: "tenant-team-a", Value: "static"},
436+
},
437+
{
438+
{Name: "__tenant_id__", Value: "team-a"},
439+
{Name: "instance", Value: "host2.team-a"},
440+
{Name: "original___tenant_id__", Value: "original-value"},
441+
},
442+
{
443+
{Name: "__tenant_id__", Value: "team-b"},
444+
{Name: "instance", Value: "host1"},
445+
{Name: "original___tenant_id__", Value: "original-value"},
446+
{Name: "tenant-team-b", Value: "static"},
447+
},
448+
{
449+
{Name: "__tenant_id__", Value: "team-b"},
450+
{Name: "instance", Value: "host2.team-b"},
451+
{Name: "original___tenant_id__", Value: "original-value"},
452+
},
453+
{
454+
{Name: "__tenant_id__", Value: "team-c"},
455+
{Name: "instance", Value: "host1"},
456+
{Name: "original___tenant_id__", Value: "original-value"},
457+
{Name: "tenant-team-c", Value: "static"},
458+
},
459+
{
460+
{Name: "__tenant_id__", Value: "team-c"},
461+
{Name: "instance", Value: "host2.team-c"},
462+
{Name: "original___tenant_id__", Value: "original-value"},
463+
},
464+
},
428465
},
429466
{
430467
name: "should return only series for team-a and team-c tenants when there is with not-equals matcher for the team-b tenant",
@@ -493,9 +530,16 @@ func TestMergeQueryable_Select(t *testing.T) {
493530
assertEqualWarnings(t, tc.expectedWarnings, seriesSet.Warnings())
494531
}
495532

533+
if tc.expectedLabels != nil {
534+
require.Equal(t, len(tc.expectedLabels), tc.expectedSeriesCount)
535+
}
536+
496537
count := 0
497-
for seriesSet.Next() {
538+
for i := 0; seriesSet.Next(); i++ {
498539
count++
540+
if tc.expectedLabels != nil {
541+
require.Equal(t, tc.expectedLabels[i], seriesSet.At().Labels(), fmt.Sprintf("labels index: %d", i))
542+
}
499543
}
500544
require.Equal(t, tc.expectedSeriesCount, count)
501545
})

0 commit comments

Comments
 (0)