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

Support max source resolution for instant queries #1431

6 changes: 5 additions & 1 deletion cmd/thanos/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ func registerQuery(m map[string]setupFunc, app *kingpin.Application, name string
replicaLabel := cmd.Flag("query.replica-label", "Label to treat as a replica indicator along which data is deduplicated. Still you will be able to query without deduplication using 'dedup=false' parameter.").
String()

instantDefaultMaxSourceResolution := modelDuration(cmd.Flag("query.instant.default.max_source_resolution", "default value for max_source_resolution for instant queries. If not set, defaults to 0s only taking raw resolution into account. 1h can be a good value if you use instant queries over time ranges that incorporate times outside of your raw-retention.").Default("0s").Hidden())

selectorLabels := cmd.Flag("selector-label", "Query selector labels that will be exposed in info endpoint (repeated).").
PlaceHolder("<name>=\"<value>\"").Strings()

Expand Down Expand Up @@ -154,6 +156,7 @@ func registerQuery(m map[string]setupFunc, app *kingpin.Application, name string
time.Duration(*dnsSDInterval),
*dnsSDResolver,
time.Duration(*unhealthyStoreTimeout),
time.Duration(*instantDefaultMaxSourceResolution),
)
}
}
Expand Down Expand Up @@ -271,6 +274,7 @@ func runQuery(
dnsSDInterval time.Duration,
dnsSDResolver string,
unhealthyStoreTimeout time.Duration,
instantDefaultMaxSourceResolution time.Duration,
) error {
// TODO(bplotka in PR #513 review): Move arguments into struct.
duplicatedStores := prometheus.NewCounter(prometheus.CounterOpts{
Expand Down Expand Up @@ -401,7 +405,7 @@ func runQuery(
ins := extpromhttp.NewInstrumentationMiddleware(reg)
ui.NewQueryUI(logger, reg, stores, flagsMap).Register(router.WithPrefix(webRoutePrefix), ins)

api := v1.NewAPI(logger, reg, engine, queryableCreator, enableAutodownsampling, enablePartialResponse)
api := v1.NewAPI(logger, reg, engine, queryableCreator, enableAutodownsampling, enablePartialResponse, instantDefaultMaxSourceResolution)

api.Register(router.WithPrefix(path.Join(webRoutePrefix, "/api/v1")), tracer, logger, ins)

Expand Down
37 changes: 23 additions & 14 deletions pkg/query/api/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ type API struct {
queryableCreate query.QueryableCreator
queryEngine *promql.Engine

enableAutodownsampling bool
enablePartialResponse bool
reg prometheus.Registerer
enableAutodownsampling bool
enablePartialResponse bool
reg prometheus.Registerer
defaultInstantQueryMaxSourceResolution time.Duration

now func() time.Time
}
Expand All @@ -115,14 +116,16 @@ func NewAPI(
c query.QueryableCreator,
enableAutodownsampling bool,
enablePartialResponse bool,
defaultInstantQueryMaxSourceResolution time.Duration,
) *API {
return &API{
logger: logger,
queryEngine: qe,
queryableCreate: c,
enableAutodownsampling: enableAutodownsampling,
enablePartialResponse: enablePartialResponse,
reg: reg,
logger: logger,
queryEngine: qe,
queryableCreate: c,
enableAutodownsampling: enableAutodownsampling,
enablePartialResponse: enablePartialResponse,
reg: reg,
defaultInstantQueryMaxSourceResolution: defaultInstantQueryMaxSourceResolution,

now: time.Now,
}
Expand Down Expand Up @@ -182,14 +185,14 @@ func (api *API) parseEnableDedupParam(r *http.Request) (enableDeduplication bool
return enableDeduplication, nil
}

func (api *API) parseDownsamplingParamMillis(r *http.Request, step time.Duration) (maxResolutionMillis int64, _ *ApiError) {
func (api *API) parseDownsamplingParamMillis(r *http.Request, defaultVal time.Duration) (maxResolutionMillis int64, _ *ApiError) {
const maxSourceResolutionParam = "max_source_resolution"
maxSourceResolution := 0 * time.Second

if api.enableAutodownsampling {
// If no max_source_resolution is specified fit at least 5 samples between steps.
maxSourceResolution = step / 5
maxSourceResolution = defaultVal
}

if val := r.FormValue(maxSourceResolutionParam); val != "" {
var err error
maxSourceResolution, err = parseDuration(val)
Expand Down Expand Up @@ -257,11 +260,16 @@ func (api *API) query(r *http.Request) (interface{}, []error, *ApiError) {
return nil, nil, apiErr
}

maxSourceResolution, apiErr := api.parseDownsamplingParamMillis(r, api.defaultInstantQueryMaxSourceResolution)
if apiErr != nil {
return nil, nil, apiErr
}

// We are starting promQL tracing span here, because we have no control over promQL code.
span, ctx := tracing.StartSpan(ctx, "promql_instant_query")
defer span.Finish()

qry, err := api.queryEngine.NewInstantQuery(api.queryableCreate(enableDedup, 0, enablePartialResponse), r.FormValue("query"), ts)
qry, err := api.queryEngine.NewInstantQuery(api.queryableCreate(enableDedup, maxSourceResolution, enablePartialResponse), r.FormValue("query"), ts)
if err != nil {
return nil, nil, &ApiError{errorBadData, err}
}
Expand Down Expand Up @@ -333,7 +341,8 @@ func (api *API) queryRange(r *http.Request) (interface{}, []error, *ApiError) {
return nil, nil, apiErr
}

maxSourceResolution, apiErr := api.parseDownsamplingParamMillis(r, step)
// If no max_source_resolution is specified fit at least 5 samples between steps.
maxSourceResolution, apiErr := api.parseDownsamplingParamMillis(r, step/5)
if apiErr != nil {
return nil, nil, apiErr
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/query/api/v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ func TestParseDownsamplingParamMillis(t *testing.T) {
v.Set("max_source_resolution", test.maxSourceResolutionParam)
r := http.Request{PostForm: v}

maxResMillis, _ := api.parseDownsamplingParamMillis(&r, test.step)
// If no max_source_resolution is specified fit at least 5 samples between steps.
maxResMillis, _ := api.parseDownsamplingParamMillis(&r, test.step/5)
if test.fail == false {
testutil.Assert(t, maxResMillis == test.result, "case %v: expected %v to be equal to %v", i, maxResMillis, test.result)
} else {
Expand Down