Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

query-tee: Add an option to shift the query times for comparison #9319

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions pkg/frontend/querymiddleware/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,17 +554,17 @@ func (c prometheusCodec) EncodeMetricsQueryRequest(ctx context.Context, r Metric
u = &url.URL{
Path: r.GetPath(),
RawQuery: url.Values{
"start": []string{encodeTime(r.GetStart())},
"end": []string{encodeTime(r.GetEnd())},
"step": []string{encodeDurationMs(r.GetStep())},
"start": []string{EncodeTime(r.GetStart())},
"end": []string{EncodeTime(r.GetEnd())},
"step": []string{EncodeDurationMs(r.GetStep())},
"query": []string{r.GetQuery()},
}.Encode(),
}
case *PrometheusInstantQueryRequest:
u = &url.URL{
Path: r.GetPath(),
RawQuery: url.Values{
"time": []string{encodeTime(r.GetTime())},
"time": []string{EncodeTime(r.GetTime())},
"query": []string{r.GetQuery()},
}.Encode(),
}
Expand Down Expand Up @@ -617,10 +617,10 @@ func (c prometheusCodec) EncodeLabelsQueryRequest(ctx context.Context, req Label
case *PrometheusLabelNamesQueryRequest:
urlValues := url.Values{}
if req.GetStart() != 0 {
urlValues["start"] = []string{encodeTime(req.Start)}
urlValues["start"] = []string{EncodeTime(req.Start)}
}
if req.GetEnd() != 0 {
urlValues["end"] = []string{encodeTime(req.End)}
urlValues["end"] = []string{EncodeTime(req.End)}
}
if len(req.GetLabelMatcherSets()) > 0 {
urlValues["match[]"] = req.GetLabelMatcherSets()
Expand All @@ -637,10 +637,10 @@ func (c prometheusCodec) EncodeLabelsQueryRequest(ctx context.Context, req Label
// does not support accessing struct members on a typeA|typeB switch
urlValues := url.Values{}
if req.GetStart() != 0 {
urlValues["start"] = []string{encodeTime(req.Start)}
urlValues["start"] = []string{EncodeTime(req.Start)}
}
if req.GetEnd() != 0 {
urlValues["end"] = []string{encodeTime(req.End)}
urlValues["end"] = []string{EncodeTime(req.End)}
}
if len(req.GetLabelMatcherSets()) > 0 {
urlValues["match[]"] = req.GetLabelMatcherSets()
Expand Down Expand Up @@ -958,12 +958,12 @@ func parseDurationMs(s string) (int64, error) {
return 0, apierror.Newf(apierror.TypeBadData, "cannot parse %q to a valid duration", s)
}

func encodeTime(t int64) string {
func EncodeTime(t int64) string {
f := float64(t) / 1.0e3
return strconv.FormatFloat(f, 'f', -1, 64)
}

func encodeDurationMs(d int64) string {
func EncodeDurationMs(d int64) string {
return strconv.FormatFloat(float64(d)/float64(time.Second/time.Millisecond), 'f', -1, 64)
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/frontend/querymiddleware/roundtrip.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import (

const (
day = 24 * time.Hour
queryRangePathSuffix = "/api/v1/query_range"
instantQueryPathSuffix = "/api/v1/query"
QueryRangePathSuffix = "/api/v1/query_range"
InstantQueryPathSuffix = "/api/v1/query"
cardinalityLabelNamesPathSuffix = "/api/v1/cardinality/label_names"
cardinalityLabelValuesPathSuffix = "/api/v1/cardinality/label_values"
cardinalityActiveSeriesPathSuffix = "/api/v1/cardinality/active_series"
Expand Down Expand Up @@ -499,11 +499,11 @@ func newQueryCountTripperware(registerer prometheus.Registerer) Tripperware {
}

func IsRangeQuery(path string) bool {
return strings.HasSuffix(path, queryRangePathSuffix)
return strings.HasSuffix(path, QueryRangePathSuffix)
}

func IsInstantQuery(path string) bool {
return strings.HasSuffix(path, instantQueryPathSuffix)
return strings.HasSuffix(path, InstantQueryPathSuffix)
}

func IsCardinalityQuery(path string) bool {
Expand Down
4 changes: 2 additions & 2 deletions pkg/frontend/querymiddleware/roundtrip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -815,12 +815,12 @@ func TestTripperware_ShouldSupportReadConsistencyOffsetsInjection(t *testing.T)
}{
"range query": {
makeRequest: func() *http.Request {
return httptest.NewRequest("GET", queryRangePathSuffix+"?start=1536673680&end=1536716880&step=120&query=up", nil)
return httptest.NewRequest("GET", QueryRangePathSuffix+"?start=1536673680&end=1536716880&step=120&query=up", nil)
},
},
"instant query": {
makeRequest: func() *http.Request {
return httptest.NewRequest("GET", instantQueryPathSuffix+"?time=1536673680&query=up", nil)
return httptest.NewRequest("GET", InstantQueryPathSuffix+"?time=1536673680&query=up", nil)
},
},
"cardinality label names": {
Expand Down
7 changes: 6 additions & 1 deletion tools/querytee/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type ProxyConfig struct {
PreferredBackend string
BackendReadTimeout time.Duration
CompareResponses bool
ShiftComparisonQueriesBy time.Duration
LogSlowQueryResponseThreshold time.Duration
ValueComparisonTolerance float64
UseRelativeError bool
Expand All @@ -43,6 +44,7 @@ type ProxyConfig struct {
BackendSkipTLSVerify bool
AddMissingTimeParamToInstantQueries bool
SecondaryBackendsRequestProportion float64
ShiftComparisonSamplingRatio float64
}

func (cfg *ProxyConfig) RegisterFlags(f *flag.FlagSet) {
Expand All @@ -69,6 +71,9 @@ func (cfg *ProxyConfig) RegisterFlags(f *flag.FlagSet) {
f.BoolVar(&cfg.PassThroughNonRegisteredRoutes, "proxy.passthrough-non-registered-routes", false, "Passthrough requests for non-registered routes to preferred backend.")
f.BoolVar(&cfg.AddMissingTimeParamToInstantQueries, "proxy.add-missing-time-parameter-to-instant-queries", true, "Add a 'time' parameter to proxied instant query requests if they do not have one.")
f.Float64Var(&cfg.SecondaryBackendsRequestProportion, "proxy.secondary-backends-request-proportion", 1.0, "Proportion of requests to send to secondary backends. Must be between 0 and 1 (inclusive), and if not 1, then -backend.preferred must be set.")
f.DurationVar(&cfg.ShiftComparisonQueriesBy, "proxy.shift-comparison-queries-by", 0, "Shift the timestamps of the queries by the given duration before querying and comparing them. This will still do the query for the preferred backend with the original timestamps but do another query with shifted timestamps for comparison.")
// Defaulted to 0 to avoid mistakes of not setting this correctly and overloading the store-gateways with shifted queries.
f.Float64Var(&cfg.ShiftComparisonSamplingRatio, "proxy.shift-comparison-sampling-ratio", 0, "Ratio of queries for which query times are shifted based on -proxy.shift-comparison-queries-by config, sampled randomly. Must be between 0 and 1 (inclusive).")
}

type Route struct {
Expand Down Expand Up @@ -232,7 +237,7 @@ func (p *Proxy) Start() error {
if p.cfg.CompareResponses {
comparator = route.ResponseComparator
}
router.Path(route.Path).Methods(route.Methods...).Handler(NewProxyEndpoint(p.backends, route, p.metrics, p.logger, comparator, p.cfg.LogSlowQueryResponseThreshold, p.cfg.SecondaryBackendsRequestProportion))
router.Path(route.Path).Methods(route.Methods...).Handler(NewProxyEndpoint(p.backends, route, p.metrics, p.logger, comparator, p.cfg))
}

if p.cfg.PassThroughNonRegisteredRoutes {
Expand Down
Loading
Loading