Skip to content

Commit e320d31

Browse files
committed
Add ingester.skip-metadata-limits flag
Signed-off-by: SungJin1212 <[email protected]>
1 parent ee387c5 commit e320d31

File tree

6 files changed

+150
-47
lines changed

6 files changed

+150
-47
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* [FEATURE] Ruler: Add support for group labels. #6665
1313
* [FEATURE] Support Parquet format: Implement parquet converter service to convert a TSDB block into Parquet. #6716
1414
* [ENHANCEMENT] Query Frontend: Change to return 400 when the tenant resolving fail. #6715
15-
* [ENHANCEMENT] Querier: Support query parameters to metadata api (/api/v1/metadata) to allow user to limit metadata to return. #6681
15+
* [ENHANCEMENT] Querier: Support query parameters to metadata api (/api/v1/metadata) to allow user to limit metadata to return. Add a `-ingester.return-all-metadata` flag to make the metadata API run when the deployment. Please set this flag to `false` to use the metadata API with the limits later. #6681 #6744
1616
* [ENHANCEMENT] Ingester: Add a `cortex_ingester_active_native_histogram_series` metric to track # of active NH series. #6695
1717
* [ENHANCEMENT] Query Frontend: Add new limit `-frontend.max-query-response-size` for total query response size after decompression in query frontend. #6607
1818
* [ENHANCEMENT] Alertmanager: Add nflog and silences maintenance metrics. #6659

docs/configuration/config-file-reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3267,6 +3267,10 @@ instance_limits:
32673267
# Maximum number of entries in the regex matchers cache. 0 to disable.
32683268
# CLI flag: -ingester.matchers-cache-max-items
32693269
[matchers_cache_max_items: <int> | default = 0]
3270+
3271+
# If enabled, the metadata API returns all metadata regardless of the limits.
3272+
# CLI flag: -ingester.skip-metadata-limits
3273+
[skip_metadata_limits: <boolean> | default = true]
32703274
```
32713275

32723276
### `ingester_client_config`

integration/ingester_metadata_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package integration
55

66
import (
77
"fmt"
8+
"strconv"
89
"strings"
910
"testing"
1011

@@ -17,6 +18,81 @@ import (
1718
"github.com/cortexproject/cortex/integration/e2ecortex"
1819
)
1920

21+
func TestMetadataAPICompatibility(t *testing.T) {
22+
oldImage := "quay.io/cortexproject/cortex:v1.19.0"
23+
s, err := e2e.NewScenario(networkName)
24+
require.NoError(t, err)
25+
defer s.Close()
26+
27+
// Start dependencies.
28+
consul := e2edb.NewConsulWithName("consul")
29+
require.NoError(t, s.StartAndWaitReady(consul))
30+
31+
baseFlags := mergeFlags(AlertmanagerLocalFlags(), BlocksStorageFlags())
32+
33+
minio := e2edb.NewMinio(9000, baseFlags["-blocks-storage.s3.bucket-name"])
34+
require.NoError(t, s.StartAndWaitReady(minio))
35+
36+
oldFlags := mergeFlags(baseFlags, map[string]string{
37+
// alert manager
38+
"-alertmanager.web.external-url": "http://localhost/alertmanager",
39+
// consul
40+
"-ring.store": "consul",
41+
"-consul.hostname": consul.NetworkHTTPEndpoint(),
42+
})
43+
44+
newFlags := mergeFlags(oldFlags, map[string]string{
45+
// ingester
46+
"-ingester.skip-metadata-limits": "true",
47+
})
48+
49+
// Start Cortex components
50+
distributor := e2ecortex.NewDistributor("distributor", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), newFlags, "")
51+
ingester := e2ecortex.NewIngester("ingester", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), newFlags, "")
52+
querier := e2ecortex.NewQuerier("querier", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), oldFlags, oldImage)
53+
require.NoError(t, s.StartAndWaitReady(distributor, ingester, querier))
54+
55+
// Wait until distributor has updated the ring.
56+
require.NoError(t, distributor.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_ring_members"}, e2e.WithLabelMatchers(
57+
labels.MustNewMatcher(labels.MatchEqual, "name", "ingester"),
58+
labels.MustNewMatcher(labels.MatchEqual, "state", "ACTIVE"))))
59+
60+
// Wait until querier has updated the ring.
61+
require.NoError(t, querier.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_ring_members"}, e2e.WithLabelMatchers(
62+
labels.MustNewMatcher(labels.MatchEqual, "name", "ingester"),
63+
labels.MustNewMatcher(labels.MatchEqual, "state", "ACTIVE"))))
64+
65+
client, err := e2ecortex.NewClient(distributor.HTTPEndpoint(), querier.HTTPEndpoint(), "", "", "user-1")
66+
require.NoError(t, err)
67+
68+
metadataMetricNum := 5
69+
metadataPerMetrics := 2
70+
metadata := make([]prompb.MetricMetadata, 0, metadataMetricNum)
71+
for i := 0; i < metadataMetricNum; i++ {
72+
for j := 0; j < metadataPerMetrics; j++ {
73+
metadata = append(metadata, prompb.MetricMetadata{
74+
MetricFamilyName: fmt.Sprintf("metadata_name_%d", i),
75+
Help: fmt.Sprintf("metadata_help_%d_%d", i, j),
76+
Unit: fmt.Sprintf("metadata_unit_%d_%d", i, j),
77+
})
78+
}
79+
}
80+
res, err := client.Push(nil, metadata...)
81+
require.NoError(t, err)
82+
require.Equal(t, 200, res.StatusCode)
83+
84+
// should return all metadata regardless of the limit
85+
maxLimit := metadataMetricNum * metadataPerMetrics
86+
for i := -1; i <= maxLimit; i++ {
87+
result, err := client.Metadata("", strconv.Itoa(i))
88+
require.NoError(t, err)
89+
require.Equal(t, metadataMetricNum, len(result))
90+
for _, metadata := range result {
91+
require.Equal(t, metadataPerMetrics, len(metadata))
92+
}
93+
}
94+
}
95+
2096
func TestIngesterMetadata(t *testing.T) {
2197
s, err := e2e.NewScenario(networkName)
2298
require.NoError(t, err)

pkg/ingester/ingester.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ type Config struct {
155155

156156
// Maximum number of entries in the matchers cache. 0 to disable.
157157
MatchersCacheMaxItems int `yaml:"matchers_cache_max_items"`
158+
159+
// If enabled, the metadata API returns all metadata regardless of the limits.
160+
SkipMetadataLimits bool `yaml:"skip_metadata_limits"`
158161
}
159162

160163
// RegisterFlags adds the flags required to config this to the given FlagSet
@@ -176,6 +179,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
176179

177180
f.BoolVar(&cfg.DisableChunkTrimming, "ingester.disable-chunk-trimming", false, "Disable trimming of matching series chunks based on query Start and End time. When disabled, the result may contain samples outside the queried time range but select performances may be improved. Note that certain query results might change by changing this option.")
178181
f.IntVar(&cfg.MatchersCacheMaxItems, "ingester.matchers-cache-max-items", 0, "Maximum number of entries in the regex matchers cache. 0 to disable.")
182+
f.BoolVar(&cfg.SkipMetadataLimits, "ingester.skip-metadata-limits", true, "If enabled, the metadata API returns all metadata regardless of the limits.")
179183

180184
cfg.DefaultLimits.RegisterFlagsWithPrefix(f, "ingester.")
181185
}
@@ -3057,7 +3061,7 @@ func (i *Ingester) getOrCreateUserMetadata(userID string) *userMetricsMetadata {
30573061
// Ensure it was not created between switching locks.
30583062
userMetadata, ok := i.usersMetadata[userID]
30593063
if !ok {
3060-
userMetadata = newMetadataMap(i.limiter, i.metrics, i.validateMetrics, userID)
3064+
userMetadata = newMetadataMap(i.limiter, i.metrics, i.validateMetrics, userID, i.cfg.SkipMetadataLimits)
30613065
i.usersMetadata[userID] = userMetadata
30623066
}
30633067
return userMetadata

pkg/ingester/user_metrics_metadata.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,33 @@ import (
1111
"github.com/cortexproject/cortex/pkg/util/validation"
1212
)
1313

14+
const (
15+
defaultLimit = -1
16+
defaultLimitPerMetric = -1
17+
)
18+
1419
// userMetricsMetadata allows metric metadata of a tenant to be held by the ingester.
1520
// Metadata is kept as a set as it can come from multiple targets that Prometheus scrapes
1621
// with the same metric name.
1722
type userMetricsMetadata struct {
18-
limiter *Limiter
19-
metrics *ingesterMetrics
20-
validateMetrics *validation.ValidateMetrics
21-
userID string
23+
limiter *Limiter
24+
metrics *ingesterMetrics
25+
validateMetrics *validation.ValidateMetrics
26+
userID string
27+
skipMetadataLimits bool
2228

2329
mtx sync.RWMutex
2430
metricToMetadata map[string]metricMetadataSet
2531
}
2632

27-
func newMetadataMap(l *Limiter, m *ingesterMetrics, v *validation.ValidateMetrics, userID string) *userMetricsMetadata {
33+
func newMetadataMap(l *Limiter, m *ingesterMetrics, v *validation.ValidateMetrics, userID string, skipMetadataLimits bool) *userMetricsMetadata {
2834
return &userMetricsMetadata{
29-
metricToMetadata: map[string]metricMetadataSet{},
30-
limiter: l,
31-
metrics: m,
32-
validateMetrics: v,
33-
userID: userID,
35+
metricToMetadata: map[string]metricMetadataSet{},
36+
limiter: l,
37+
metrics: m,
38+
validateMetrics: v,
39+
userID: userID,
40+
skipMetadataLimits: skipMetadataLimits,
3441
}
3542
}
3643

@@ -88,8 +95,17 @@ func (mm *userMetricsMetadata) purge(deadline time.Time) {
8895
func (mm *userMetricsMetadata) toClientMetadata(req *client.MetricsMetadataRequest) []*cortexpb.MetricMetadata {
8996
mm.mtx.RLock()
9097
defer mm.mtx.RUnlock()
98+
9199
r := make([]*cortexpb.MetricMetadata, 0, len(mm.metricToMetadata))
92-
if req.Limit == 0 {
100+
limit := req.Limit
101+
limitPerMetric := req.LimitPerMetric
102+
103+
if mm.skipMetadataLimits {
104+
// set limit and limitPerMetric to default
105+
limit = defaultLimit
106+
limitPerMetric = defaultLimitPerMetric
107+
}
108+
if limit == 0 {
93109
return r
94110
}
95111

@@ -99,16 +115,16 @@ func (mm *userMetricsMetadata) toClientMetadata(req *client.MetricsMetadataReque
99115
return r
100116
}
101117

102-
metadataSet.add(req.LimitPerMetric, &r)
118+
metadataSet.add(limitPerMetric, &r)
103119
return r
104120
}
105121

106122
var metrics int64
107123
for _, set := range mm.metricToMetadata {
108-
if req.Limit > 0 && metrics >= req.Limit {
124+
if limit > 0 && metrics >= limit {
109125
break
110126
}
111-
set.add(req.LimitPerMetric, &r)
127+
set.add(limitPerMetric, &r)
112128
metrics++
113129
}
114130
return r

pkg/ingester/user_metrics_metadata_test.go

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ import (
1414
"github.com/cortexproject/cortex/pkg/util/validation"
1515
)
1616

17-
const (
18-
defaultLimit = -1
19-
defaultLimitPerMetric = -1
20-
)
21-
2217
func Test_UserMetricsMetadata(t *testing.T) {
2318
userId := "user-1"
2419

@@ -43,33 +38,13 @@ func Test_UserMetricsMetadata(t *testing.T) {
4338
require.NoError(t, err)
4439
limiter := NewLimiter(overrides, nil, util.ShardingStrategyDefault, true, 1, false, "")
4540

46-
userMetricsMetadata := newMetadataMap(limiter, m, validation.NewValidateMetrics(reg), userId)
47-
48-
addMetricMetadata := func(name string, i int) {
49-
metadata := &cortexpb.MetricMetadata{
50-
MetricFamilyName: fmt.Sprintf("%s_%d", name, i),
51-
Type: cortexpb.GAUGE,
52-
Help: fmt.Sprintf("a help for %s", name),
53-
Unit: fmt.Sprintf("a unit for %s", name),
54-
}
55-
56-
err := userMetricsMetadata.add(name, metadata)
57-
require.NoError(t, err)
58-
}
59-
60-
metadataNumPerMetric := 3
61-
for _, m := range []string{"metric1", "metric2"} {
62-
for i := range metadataNumPerMetric {
63-
addMetricMetadata(m, i)
64-
}
65-
}
66-
6741
tests := []struct {
68-
description string
69-
limit int64
70-
limitPerMetric int64
71-
metric string
72-
expectedLength int
42+
description string
43+
limit int64
44+
limitPerMetric int64
45+
metric string
46+
expectedLength int
47+
skipMetadataLimits bool
7348
}{
7449
{
7550
description: "limit: 1",
@@ -122,10 +97,38 @@ func Test_UserMetricsMetadata(t *testing.T) {
12297
metric: "dummy",
12398
expectedLength: 0,
12499
},
100+
{
101+
description: "enable skipMetadataLimits",
102+
limit: 1,
103+
limitPerMetric: 2,
104+
expectedLength: 2 * 3, // # of metric * metadataNumPerMetric
105+
skipMetadataLimits: true,
106+
},
125107
}
126108

127109
for _, test := range tests {
128110
t.Run(test.description, func(t *testing.T) {
111+
userMetricsMetadata := newMetadataMap(limiter, m, validation.NewValidateMetrics(reg), userId, test.skipMetadataLimits)
112+
113+
addMetricMetadata := func(name string, i int) {
114+
metadata := &cortexpb.MetricMetadata{
115+
MetricFamilyName: fmt.Sprintf("%s_%d", name, i),
116+
Type: cortexpb.GAUGE,
117+
Help: fmt.Sprintf("a help for %s", name),
118+
Unit: fmt.Sprintf("a unit for %s", name),
119+
}
120+
121+
err := userMetricsMetadata.add(name, metadata)
122+
require.NoError(t, err)
123+
}
124+
125+
metadataNumPerMetric := 3
126+
for _, m := range []string{"metric1", "metric2"} {
127+
for i := range metadataNumPerMetric {
128+
addMetricMetadata(m, i)
129+
}
130+
}
131+
129132
req := &client.MetricsMetadataRequest{Limit: test.limit, LimitPerMetric: test.limitPerMetric, Metric: test.metric}
130133

131134
r := userMetricsMetadata.toClientMetadata(req)

0 commit comments

Comments
 (0)