Skip to content

Commit bb7ba54

Browse files
eeldalyfriedrichg
andauthored
Query priority based on operation (#7128)
* Add query priority for all operations Signed-off-by: Essam Eldaly <[email protected]> * Move query reject to before query priority Signed-off-by: Essam Eldaly <[email protected]> * Update tests and changelog Signed-off-by: Essam Eldaly <[email protected]> * Fix old test to support change Signed-off-by: Essam Eldaly <[email protected]> * Prioritize top most priority to be consistent with query priorities Signed-off-by: Essam Eldaly <[email protected]> * Add second api to tests Signed-off-by: Essam Eldaly <[email protected]> * Fix test urls Signed-off-by: Essam Eldaly <[email protected]> --------- Signed-off-by: Essam Eldaly <[email protected]> Signed-off-by: Friedrich Gonzalez <[email protected]> Co-authored-by: Friedrich Gonzalez <[email protected]>
1 parent 194fbcb commit bb7ba54

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [ENHANCEMENT] Distributor: Add count, spans, and buckets validations for native histogram. #7072
1313
* [ENHANCEMENT] Alertmanager/Ruler: Introduce a user scanner to reduce the number of list calls to object storage. #6999
1414
* [ENHANCEMENT] Ruler: Add DecodingConcurrency config flag for Thanos Engine. #7118
15+
* [ENHANCEMENT] Query Frontend: Add query priority based on operation. #7128
1516
* [ENHANCEMENT] Compactor: Avoid double compaction by cleaning partition files in 2 cycles. #7129
1617
* [ENHANCEMENT] Distributor: Optimize memory usage by recycling v2 requests. #7131
1718
* [BUGFIX] Ring: Change DynamoDB KV to retry indefinitely for WatchKey. #7088

pkg/querier/tripperware/query_attribute_matcher.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func rejectQueryOrSetPriority(r *http.Request, now time.Time, lookbackDelta time
2222
return nil
2323
}
2424
op := getOperation(r)
25+
reqStats := stats.FromContext(r.Context())
2526

2627
if op == "query" || op == "query_range" {
2728
query := r.FormValue("query")
@@ -40,7 +41,6 @@ func rejectQueryOrSetPriority(r *http.Request, now time.Time, lookbackDelta time
4041
}
4142
}
4243

43-
reqStats := stats.FromContext(r.Context())
4444
reqStats.SetDataSelectMaxTime(maxTime)
4545
reqStats.SetDataSelectMinTime(minTime)
4646

@@ -55,13 +55,24 @@ func rejectQueryOrSetPriority(r *http.Request, now time.Time, lookbackDelta time
5555
}
5656
reqStats.SetPriority(queryPriority.DefaultPriority)
5757
}
58-
}
58+
} else {
59+
if queryReject := limits.QueryRejection(userStr); queryReject.Enabled && (op == "series" || op == "labels" || op == "label_values") {
60+
for _, attribute := range queryReject.QueryAttributes {
61+
if matchAttributeForMetadataQuery(attribute, op, r, now) {
62+
rejectedQueriesPerTenant.WithLabelValues(op, userStr).Inc()
63+
return httpgrpc.Errorf(http.StatusUnprocessableEntity, QueryRejectErrorMessage)
64+
}
65+
}
66+
}
5967

60-
if queryReject := limits.QueryRejection(userStr); queryReject.Enabled && (op == "series" || op == "labels" || op == "label_values") {
61-
for _, attribute := range queryReject.QueryAttributes {
62-
if matchAttributeForMetadataQuery(attribute, op, r, now) {
63-
rejectedQueriesPerTenant.WithLabelValues(op, userStr).Inc()
64-
return httpgrpc.Errorf(http.StatusUnprocessableEntity, QueryRejectErrorMessage)
68+
if queryPriority := limits.QueryPriority(userStr); queryPriority.Enabled && len(queryPriority.Priorities) != 0 {
69+
for _, priority := range queryPriority.Priorities {
70+
for _, attribute := range priority.QueryAttributes {
71+
if matchAttributeForMetadataQuery(attribute, op, r, now) {
72+
reqStats.SetPriority(priority.Priority)
73+
break
74+
}
75+
}
6576
}
6677
}
6778
}
@@ -81,6 +92,8 @@ func getOperation(r *http.Request) string {
8192
return "labels"
8293
case strings.HasSuffix(r.URL.Path, "/values"):
8394
return "label_values"
95+
case strings.HasSuffix(r.URL.Path, "/metadata"):
96+
return "metadata"
8497
default:
8598
return "other"
8699
}

pkg/querier/tripperware/query_attribute_matcher_test.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ func Test_rejectQueryOrSetPriorityShouldReturnDefaultPriorityIfNotEnabledOrInval
5959
path: "/api/v1/query?time=1536716898&query=",
6060
expectedError: httpgrpc.Errorf(http.StatusBadRequest, "unknown position: parse error: no expression found in input"),
6161
},
62-
"should miss if it's metadata query and only priority is enabled": {
62+
"should set priority if it's metadata query and only priority is enabled": {
6363
queryPriorityEnabled: true,
6464
queryRejectionEnabled: false,
6565
path: "/api/v1/labels?match[]",
66+
expectedPriority: 1,
6667
},
6768
"should set priority if regex match and rejection disabled": {
6869
queryPriorityEnabled: true,
@@ -706,3 +707,57 @@ func Test_matchAttributeForExpressionQueryShouldMatchUserAgentRegex(t *testing.T
706707
}
707708

708709
}
710+
711+
func Test_rejectQueryOrSetPriorityShouldMatchOnApiType(t *testing.T) {
712+
713+
limits := mockLimits{queryPriority: validation.QueryPriority{
714+
Priorities: []validation.PriorityDef{
715+
{
716+
Priority: 7,
717+
QueryAttributes: []validation.QueryAttribute{
718+
{
719+
ApiType: "metadata",
720+
},
721+
},
722+
},
723+
{
724+
Priority: 6,
725+
QueryAttributes: []validation.QueryAttribute{
726+
{
727+
ApiType: "series",
728+
},
729+
},
730+
},
731+
},
732+
},
733+
}
734+
735+
type testCase struct {
736+
path string
737+
expectedPriority int64
738+
}
739+
740+
tests := map[string]testCase{
741+
"should set priority based on api type for metadata": {
742+
path: "/api/v1/metadata?limit=1",
743+
expectedPriority: 7,
744+
},
745+
"should set priority based on api type for series": {
746+
path: "/api/v1/series",
747+
expectedPriority: 6,
748+
},
749+
}
750+
751+
for testName, testData := range tests {
752+
t.Run(testName, func(t *testing.T) {
753+
req, err := http.NewRequest("GET", testData.path, http.NoBody)
754+
require.NoError(t, err)
755+
reqStats, ctx := stats.ContextWithEmptyStats(context.Background())
756+
req = req.WithContext(ctx)
757+
limits.queryPriority.Enabled = true
758+
resultErr := rejectQueryOrSetPriority(req, time.Now(), time.Duration(1), limits, "", rejectedQueriesPerTenant)
759+
assert.NoError(t, resultErr)
760+
assert.Equal(t, testData.expectedPriority, reqStats.Priority)
761+
})
762+
}
763+
}

0 commit comments

Comments
 (0)