Skip to content

Commit 9e1fa22

Browse files
committed
Add --query-range.request-downsampled flag to Query Frontend (thanos-io#2641)
Signed-off-by: Vladimir Kononov <[email protected]>
1 parent c7a171f commit 9e1fa22

File tree

5 files changed

+113
-1
lines changed

5 files changed

+113
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ We use _breaking :warning:_ to mark changes that are not backward compatible (re
1515
### Added
1616

1717
- [#3700](https://github.com/thanos-io/thanos/pull/3700) ui: make old bucket viewer UI work with vanilla Prometheus blocks
18+
- [#2641](https://github.com/thanos-io/thanos/issues/2641) Query Frontend: Added `--query-range.request-downsampled` flag enabling additional queries for downsampled data in case of empty or incomplete response to range request.
1819

1920
### Changed
2021

cmd/thanos/query_frontend.go

+3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ func registerQueryFrontend(app *extkingpin.App) {
6565
cmd.Flag("query-range.align-range-with-step", "Mutate incoming queries to align their start and end with their step for better cache-ability. Note: Grafana dashboards do that by default.").
6666
Default("true").BoolVar(&cfg.QueryRangeConfig.AlignRangeWithStep)
6767

68+
cmd.Flag("query-range.request-downsampled", "Make additional query for downsampled data in case of empty or incomplete response to range request.").
69+
Default("true").BoolVar(&cfg.QueryRangeConfig.RequestDownsampled)
70+
6871
cmd.Flag("query-range.split-interval", "Split query range requests by an interval and execute in parallel, it should be greater than 0 when query-range.response-cache-config is configured.").
6972
Default("24h").DurationVar(&cfg.QueryRangeConfig.SplitQueriesByInterval)
7073

pkg/queryfrontend/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ type QueryRangeConfig struct {
162162
CachePathOrContent extflag.PathOrContent
163163

164164
AlignRangeWithStep bool
165+
RequestDownsampled bool
165166
SplitQueriesByInterval time.Duration
166167
MaxRetries int
167168
Limits *cortexvalidation.Limits

pkg/queryfrontend/downsampled.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package queryfrontend
2+
3+
import (
4+
"context"
5+
"github.com/cortexproject/cortex/pkg/querier/queryrange"
6+
"github.com/prometheus/client_golang/prometheus"
7+
"github.com/prometheus/client_golang/prometheus/promauto"
8+
"github.com/thanos-io/thanos/pkg/compact/downsample"
9+
)
10+
11+
// DownsampledMiddleware creates a new Middleware that requests downsampled data
12+
// should response to original request with auto max_source_resolution not contain data points.
13+
func DownsampledMiddleware(merger queryrange.Merger, registerer prometheus.Registerer) queryrange.Middleware {
14+
return queryrange.MiddlewareFunc(func(next queryrange.Handler) queryrange.Handler {
15+
return downsampled{
16+
next: next,
17+
merger: merger,
18+
extraCounter: promauto.With(registerer).NewCounter(prometheus.CounterOpts{
19+
Namespace: "thanos",
20+
Name: "frontend_downsampled_extra_queries_total",
21+
Help: "Total number of extra queries for downsampled data",
22+
}),
23+
}
24+
})
25+
}
26+
27+
type downsampled struct {
28+
next queryrange.Handler
29+
merger queryrange.Merger
30+
31+
// Metrics.
32+
extraCounter prometheus.Counter
33+
}
34+
35+
var resolutions = []int64{downsample.ResLevel1, downsample.ResLevel2}
36+
37+
func (d downsampled) Do(ctx context.Context, req queryrange.Request) (queryrange.Response, error) {
38+
tqrr, ok := req.(*ThanosQueryRangeRequest)
39+
if !ok || !tqrr.AutoDownsampling {
40+
return d.next.Do(ctx, req)
41+
}
42+
43+
var (
44+
resps = make([]queryrange.Response, 0)
45+
resp queryrange.Response
46+
err error
47+
i int
48+
)
49+
50+
for {
51+
if i >= len(resolutions) {
52+
break
53+
} else if i > 0 {
54+
d.extraCounter.Inc()
55+
}
56+
r := *tqrr
57+
resp, err = d.next.Do(ctx, &r)
58+
if err != nil {
59+
return nil, err
60+
}
61+
resps = append(resps, resp)
62+
// Set MaxSourceResolution for next request, if any.
63+
for i < len(resolutions) {
64+
if tqrr.MaxSourceResolution < resolutions[i] {
65+
tqrr.AutoDownsampling = false
66+
tqrr.MaxSourceResolution = resolutions[i]
67+
break
68+
}
69+
i++
70+
}
71+
m := minResponseTimestampMs(resp)
72+
switch m {
73+
case tqrr.Start: // Response not impacted by retention policy.
74+
break
75+
case 0: // Empty response, retry with higher MaxSourceResolution.
76+
continue
77+
default: // Data partially present, query for empty part with higher MaxSourceResolution.
78+
tqrr.End = m - tqrr.Step
79+
}
80+
if tqrr.Start > tqrr.End {
81+
break
82+
}
83+
}
84+
response, err := d.merger.MergeResponse(resps...)
85+
if err != nil {
86+
return nil, err
87+
}
88+
return response, nil
89+
}
90+
91+
func minResponseTimestampMs(r queryrange.Response) (min int64) {
92+
var pr = r.(*queryrange.PrometheusResponse)
93+
for _, ss := range pr.Data.Result {
94+
if min == 0 || ss.Samples[0].TimestampMs < min {
95+
min = ss.Samples[0].TimestampMs
96+
}
97+
}
98+
return min
99+
}

pkg/queryfrontend/roundtrip.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func getOperation(r *http.Request) string {
131131
}
132132

133133
// newQueryRangeTripperware returns a Tripperware for range queries configured with middlewares of
134-
// limit, step align, split by interval, cache requests and retry.
134+
// limit, step align, downsampled, split by interval, cache requests and retry.
135135
func newQueryRangeTripperware(
136136
config QueryRangeConfig,
137137
limits queryrange.Limits,
@@ -151,6 +151,14 @@ func newQueryRangeTripperware(
151151
)
152152
}
153153

154+
if config.RequestDownsampled {
155+
queryRangeMiddleware = append(
156+
queryRangeMiddleware,
157+
queryrange.InstrumentMiddleware("downsampled", m),
158+
DownsampledMiddleware(codec, reg),
159+
)
160+
}
161+
154162
queryIntervalFn := func(_ queryrange.Request) time.Duration {
155163
return config.SplitQueriesByInterval
156164
}

0 commit comments

Comments
 (0)