@@ -1863,13 +1863,17 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1863
1863
matchers []* labels.Matcher
1864
1864
expectedResult []metric.Metric
1865
1865
expectedIngesters int
1866
+ queryLimiter * limiter.QueryLimiter
1867
+ expectedErr error
1866
1868
}{
1867
1869
"should return an empty response if no metric match" : {
1868
1870
matchers : []* labels.Matcher {
1869
1871
mustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "unknown" ),
1870
1872
},
1871
1873
expectedResult : []metric.Metric {},
1872
1874
expectedIngesters : numIngesters ,
1875
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1876
+ expectedErr : nil ,
1873
1877
},
1874
1878
"should filter metrics by single matcher" : {
1875
1879
matchers : []* labels.Matcher {
@@ -1880,6 +1884,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1880
1884
{Metric : util .LabelsToMetric (fixtures [1 ].lbls )},
1881
1885
},
1882
1886
expectedIngesters : numIngesters ,
1887
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1888
+ expectedErr : nil ,
1883
1889
},
1884
1890
"should filter metrics by multiple matchers" : {
1885
1891
matchers : []* labels.Matcher {
@@ -1890,6 +1896,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1890
1896
{Metric : util .LabelsToMetric (fixtures [0 ].lbls )},
1891
1897
},
1892
1898
expectedIngesters : numIngesters ,
1899
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1900
+ expectedErr : nil ,
1893
1901
},
1894
1902
"should return all matching metrics even if their FastFingerprint collide" : {
1895
1903
matchers : []* labels.Matcher {
@@ -1900,6 +1908,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1900
1908
{Metric : util .LabelsToMetric (fixtures [4 ].lbls )},
1901
1909
},
1902
1910
expectedIngesters : numIngesters ,
1911
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1912
+ expectedErr : nil ,
1903
1913
},
1904
1914
"should query only ingesters belonging to tenant's subring if shuffle sharding is enabled" : {
1905
1915
shuffleShardEnabled : true ,
@@ -1912,6 +1922,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1912
1922
{Metric : util .LabelsToMetric (fixtures [1 ].lbls )},
1913
1923
},
1914
1924
expectedIngesters : 3 ,
1925
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1926
+ expectedErr : nil ,
1915
1927
},
1916
1928
"should query all ingesters if shuffle sharding is enabled but shard size is 0" : {
1917
1929
shuffleShardEnabled : true ,
@@ -1924,6 +1936,30 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1924
1936
{Metric : util .LabelsToMetric (fixtures [1 ].lbls )},
1925
1937
},
1926
1938
expectedIngesters : numIngesters ,
1939
+ queryLimiter : limiter .NewQueryLimiter (0 , 0 , 0 ),
1940
+ expectedErr : nil ,
1941
+ },
1942
+ "should return err if series limit is exhausted" : {
1943
+ shuffleShardEnabled : true ,
1944
+ shuffleShardSize : 0 ,
1945
+ matchers : []* labels.Matcher {
1946
+ mustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "test_1" ),
1947
+ },
1948
+ expectedResult : nil ,
1949
+ expectedIngesters : numIngesters ,
1950
+ queryLimiter : limiter .NewQueryLimiter (1 , 0 , 0 ),
1951
+ expectedErr : validation .LimitError (fmt .Sprintf (limiter .ErrMaxSeriesHit , 1 )),
1952
+ },
1953
+ "should not exhaust series limit when only one series is fetched" : {
1954
+ matchers : []* labels.Matcher {
1955
+ mustNewMatcher (labels .MatchEqual , model .MetricNameLabel , "test_2" ),
1956
+ },
1957
+ expectedResult : []metric.Metric {
1958
+ {Metric : util .LabelsToMetric (fixtures [2 ].lbls )},
1959
+ },
1960
+ expectedIngesters : numIngesters ,
1961
+ queryLimiter : limiter .NewQueryLimiter (1 , 0 , 0 ),
1962
+ expectedErr : nil ,
1927
1963
},
1928
1964
}
1929
1965
@@ -1943,6 +1979,7 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1943
1979
1944
1980
// Push fixtures
1945
1981
ctx := user .InjectOrgID (context .Background (), "test" )
1982
+ ctx = limiter .AddQueryLimiterToContext (ctx , testData .queryLimiter )
1946
1983
1947
1984
for _ , series := range fixtures {
1948
1985
req := mockWriteRequest ([]labels.Labels {series .lbls }, series .value , series .timestamp )
@@ -1951,6 +1988,12 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1951
1988
}
1952
1989
1953
1990
metrics , err := ds [0 ].MetricsForLabelMatchers (ctx , now , now , testData .matchers ... )
1991
+
1992
+ if testData .expectedErr != nil {
1993
+ assert .EqualError (t , err , testData .expectedErr .Error ())
1994
+ return
1995
+ }
1996
+
1954
1997
require .NoError (t , err )
1955
1998
assert .ElementsMatch (t , testData .expectedResult , metrics )
1956
1999
@@ -1963,6 +2006,97 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
1963
2006
}
1964
2007
}
1965
2008
2009
+ func BenchmarkDistributor_MetricsForLabelMatchers (b * testing.B ) {
2010
+ const (
2011
+ numIngesters = 100
2012
+ numSeriesPerRequest = 100
2013
+ )
2014
+
2015
+ tests := map [string ]struct {
2016
+ prepareConfig func (limits * validation.Limits )
2017
+ prepareSeries func () ([]labels.Labels , []cortexpb.Sample )
2018
+ matchers []* labels.Matcher
2019
+ queryLimiter * limiter.QueryLimiter
2020
+ expectedErr error
2021
+ }{
2022
+ "get series within limits" : {
2023
+ prepareConfig : func (limits * validation.Limits ) {},
2024
+ prepareSeries : func () ([]labels.Labels , []cortexpb.Sample ) {
2025
+ metrics := make ([]labels.Labels , numSeriesPerRequest )
2026
+ samples := make ([]cortexpb.Sample , numSeriesPerRequest )
2027
+
2028
+ for i := 0 ; i < numSeriesPerRequest ; i ++ {
2029
+ lbls := labels .NewBuilder (labels.Labels {{Name : model .MetricNameLabel , Value : fmt .Sprintf ("foo_%d" , i )}})
2030
+ for i := 0 ; i < 10 ; i ++ {
2031
+ lbls .Set (fmt .Sprintf ("name_%d" , i ), fmt .Sprintf ("value_%d" , i ))
2032
+ }
2033
+
2034
+ metrics [i ] = lbls .Labels ()
2035
+ samples [i ] = cortexpb.Sample {
2036
+ Value : float64 (i ),
2037
+ TimestampMs : time .Now ().UnixNano () / int64 (time .Millisecond ),
2038
+ }
2039
+ }
2040
+
2041
+ return metrics , samples
2042
+ },
2043
+ matchers : []* labels.Matcher {
2044
+ mustNewMatcher (labels .MatchRegexp , model .MetricNameLabel , "foo.+" ),
2045
+ },
2046
+ queryLimiter : limiter .NewQueryLimiter (100 , 0 , 0 ),
2047
+ expectedErr : nil ,
2048
+ },
2049
+ }
2050
+
2051
+ for testName , testData := range tests {
2052
+ b .Run (testName , func (b * testing.B ) {
2053
+ // Create distributor
2054
+ ds , ingesters , _ , _ := prepare (b , prepConfig {
2055
+ numIngesters : numIngesters ,
2056
+ happyIngesters : numIngesters ,
2057
+ numDistributors : 1 ,
2058
+ shardByAllLabels : true ,
2059
+ shuffleShardEnabled : false ,
2060
+ shuffleShardSize : 0 ,
2061
+ })
2062
+
2063
+ // Push fixtures
2064
+ ctx := user .InjectOrgID (context .Background (), "test" )
2065
+ ctx = limiter .AddQueryLimiterToContext (ctx , testData .queryLimiter )
2066
+
2067
+ // Prepare the series to remote write before starting the benchmark.
2068
+ metrics , samples := testData .prepareSeries ()
2069
+
2070
+ if _ , err := ds [0 ].Push (ctx , cortexpb .ToWriteRequest (metrics , samples , nil , cortexpb .API )); err != nil {
2071
+ b .Fatalf ("error pushing to distributor %v" , err )
2072
+ }
2073
+
2074
+ // Run the benchmark.
2075
+ b .ReportAllocs ()
2076
+ b .ResetTimer ()
2077
+
2078
+ for n := 0 ; n < b .N ; n ++ {
2079
+ now := model .Now ()
2080
+ metrics , err := ds [0 ].MetricsForLabelMatchers (ctx , now , now , testData .matchers ... )
2081
+
2082
+ if testData .expectedErr != nil {
2083
+ assert .EqualError (b , err , testData .expectedErr .Error ())
2084
+ return
2085
+ }
2086
+
2087
+ require .NoError (b , err )
2088
+
2089
+ // Check how many ingesters have been queried.
2090
+ // Due to the quorum the distributor could cancel the last request towards ingesters
2091
+ // if all other ones are successful, so we're good either has been queried X or X-1
2092
+ // ingesters.
2093
+ assert .Contains (b , []int {numIngesters , numIngesters - 1 }, countMockIngestersCalls (ingesters , "MetricsForLabelMatchers" ))
2094
+ assert .Equal (b , numSeriesPerRequest , len (metrics ))
2095
+ }
2096
+ })
2097
+ }
2098
+ }
2099
+
1966
2100
func TestDistributor_MetricsMetadata (t * testing.T ) {
1967
2101
const numIngesters = 5
1968
2102
@@ -2058,7 +2192,7 @@ type prepConfig struct {
2058
2192
errFail error
2059
2193
}
2060
2194
2061
- func prepare (t * testing.T , cfg prepConfig ) ([]* Distributor , []mockIngester , []* prometheus.Registry , * ring.Ring ) {
2195
+ func prepare (tb testing.TB , cfg prepConfig ) ([]* Distributor , []mockIngester , []* prometheus.Registry , * ring.Ring ) {
2062
2196
ingesters := []mockIngester {}
2063
2197
for i := 0 ; i < cfg .happyIngesters ; i ++ {
2064
2198
ingesters = append (ingesters , mockIngester {
@@ -2095,7 +2229,7 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2095
2229
}
2096
2230
2097
2231
kvStore , closer := consul .NewInMemoryClient (ring .GetCodec (), log .NewNopLogger (), nil )
2098
- t .Cleanup (func () { assert .NoError (t , closer .Close ()) })
2232
+ tb .Cleanup (func () { assert .NoError (tb , closer .Close ()) })
2099
2233
2100
2234
err := kvStore .CAS (context .Background (), ingester .RingKey ,
2101
2235
func (_ interface {}) (interface {}, bool , error ) {
@@ -2104,7 +2238,7 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2104
2238
}, true , nil
2105
2239
},
2106
2240
)
2107
- require .NoError (t , err )
2241
+ require .NoError (tb , err )
2108
2242
2109
2243
// Use a default replication factor of 3 if there isn't a provided replication factor.
2110
2244
rf := cfg .replicationFactor
@@ -2119,10 +2253,10 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2119
2253
HeartbeatTimeout : 60 * time .Minute ,
2120
2254
ReplicationFactor : rf ,
2121
2255
}, ingester .RingKey , ingester .RingKey , nil , nil )
2122
- require .NoError (t , err )
2123
- require .NoError (t , services .StartAndAwaitRunning (context .Background (), ingestersRing ))
2256
+ require .NoError (tb , err )
2257
+ require .NoError (tb , services .StartAndAwaitRunning (context .Background (), ingestersRing ))
2124
2258
2125
- test .Poll (t , time .Second , cfg .numIngesters , func () interface {} {
2259
+ test .Poll (tb , time .Second , cfg .numIngesters , func () interface {} {
2126
2260
return ingestersRing .InstancesCount ()
2127
2261
})
2128
2262
@@ -2163,7 +2297,7 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2163
2297
if cfg .enableTracker {
2164
2298
codec := GetReplicaDescCodec ()
2165
2299
ringStore , closer := consul .NewInMemoryClient (codec , log .NewNopLogger (), nil )
2166
- t .Cleanup (func () { assert .NoError (t , closer .Close ()) })
2300
+ tb .Cleanup (func () { assert .NoError (tb , closer .Close ()) })
2167
2301
mock := kv .PrefixClient (ringStore , "prefix" )
2168
2302
distributorCfg .HATrackerConfig = HATrackerConfig {
2169
2303
EnableHATracker : true ,
@@ -2175,12 +2309,12 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2175
2309
}
2176
2310
2177
2311
overrides , err := validation .NewOverrides (* cfg .limits , nil )
2178
- require .NoError (t , err )
2312
+ require .NoError (tb , err )
2179
2313
2180
2314
reg := prometheus .NewPedanticRegistry ()
2181
2315
d , err := New (distributorCfg , clientConfig , overrides , ingestersRing , true , reg , log .NewNopLogger ())
2182
- require .NoError (t , err )
2183
- require .NoError (t , services .StartAndAwaitRunning (context .Background (), d ))
2316
+ require .NoError (tb , err )
2317
+ require .NoError (tb , services .StartAndAwaitRunning (context .Background (), d ))
2184
2318
2185
2319
distributors = append (distributors , d )
2186
2320
registries = append (registries , reg )
@@ -2189,12 +2323,12 @@ func prepare(t *testing.T, cfg prepConfig) ([]*Distributor, []mockIngester, []*p
2189
2323
// If the distributors ring is setup, wait until the first distributor
2190
2324
// updates to the expected size
2191
2325
if distributors [0 ].distributorsRing != nil {
2192
- test .Poll (t , time .Second , cfg .numDistributors , func () interface {} {
2326
+ test .Poll (tb , time .Second , cfg .numDistributors , func () interface {} {
2193
2327
return distributors [0 ].distributorsLifeCycler .HealthyInstancesCount ()
2194
2328
})
2195
2329
}
2196
2330
2197
- t .Cleanup (func () { stopAll (distributors , ingestersRing ) })
2331
+ tb .Cleanup (func () { stopAll (distributors , ingestersRing ) })
2198
2332
2199
2333
return distributors , ingesters , registries , ingestersRing
2200
2334
}
0 commit comments