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

Split by range of instant queries #5662

Merged
merged 33 commits into from
Apr 7, 2022

Conversation

ssncferreira
Copy link
Contributor

@ssncferreira ssncferreira commented Mar 17, 2022

What this PR does / why we need it:

This PR introduces a new middleware that splits instant queries with a large range into several smaller sub-queries to parallelize their execution.

The interval by which instant queries are split is defined by the setting split_queries_by_interval.

Note: Using a too small split interval may result in a lot of sub-queries, which can cause the query queue to fill up and make requests slower than faster.

Special notes for your reviewer:

The following screenshot shows the p99 query latency for old and new implementation, using a split interval of 1d and various vector and range aggregations with 7d and 30d ranges respectively.

2022-04-05_13-22

Checklist

  • Documentation added
  • Tests updated
  • Add an entry in the CHANGELOG.md about the changes.

@ssncferreira ssncferreira force-pushed the instant-query-splitting-v3-optimizations branch 4 times, most recently from 084407e to 6449bf9 Compare March 18, 2022 10:18
@chaudum chaudum force-pushed the instant-query-splitting-v3-optimizations branch from 797d2b1 to e116c31 Compare March 29, 2022 11:08
@chaudum chaudum marked this pull request as ready for review March 29, 2022 11:09
@chaudum chaudum requested a review from a team as a code owner March 29, 2022 11:09
@chaudum chaudum changed the title Split by range on Instant queries POC Split by range if instant queries Mar 29, 2022
@chaudum chaudum changed the title Split by range if instant queries Split by range of instant queries Mar 29, 2022
return nil, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
}

interval := validation.SmallestPositiveNonZeroDurationPerTenant(tenants, s.limits.QuerySplitDuration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The split duration is still subject to change and requires further testing. We may need to introduce a second setting, or even calculate the split duration dynamically based on the range of the query.

Copy link
Member

@owen-d owen-d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good, but it's in need of some equivalence testing (see TestMappingEquivalence in logql/downstream_test.go)

pkg/logql/rangemapper.go Show resolved Hide resolved
Operation: overrideDownstream.Operation,
}
}
return &syntax.BinOpExpr{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever how you've accounted for all this inside logql evaluation!

pkg/logql/rangemapper.go Show resolved Hide resolved
// Currently, it is sending the last inner expression grouping dowstream.
// Which grouping should be sent downstream?
var vectorAggrPushdown *syntax.VectorAggregationExpr
if expr.Grouping != nil && expr.Grouping.Groups != nil && expr.Operation != syntax.OpTypeCount {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we need the expr.Grouping.Groups != nil check. Can't we also push down a sum (foo), which is effectively sum by () (foo)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check.

pkg/logql/rangemapper.go Show resolved Hide resolved
pkg/logql/rangemapper.go Outdated Show resolved Hide resolved
pkg/logql/rangemapper_test.go Show resolved Hide resolved
pkg/logql/rangemapper.go Show resolved Hide resolved
}

switch res.Data.Type() {
case parser.ValueTypeMatrix:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: by having two separate middlewares, we're converting back and forth between promtheus types (Matrix, Vector, Scalar) and queryrange.Response types multiple times in each query (since each middleware has it's own logql engine which downstreams. This is probably fine for simplicity's sake unless we find a better way to handle this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also parse the query each time. That's probably not as bad. In any case it feels these middlewares could be refactored at some point and "just" pass down the modified query or query plan.

@chaudum
Copy link
Contributor

chaudum commented Apr 4, 2022

This is looking really good, but it's in need of some equivalence testing (see TestMappingEquivalence in logql/downstream_test.go)

There are a bunch of range aggregation and vector aggregation queries tested in TestRangeMappingEquivalence in downstream_test.go.
Or do you mean, adding an additional test with the new range mapper and the shard mapper as in TestMappingEquivalence?

@owen-d
Copy link
Member

owen-d commented Apr 4, 2022

I've taken another look and found the equivalence tests -- nice work! I've also dismissed a few of my earlier comments. This is looking about ready, @cyriltovena do you want to give it another pair of 👀 ?

@chaudum
Copy link
Contributor

chaudum commented Apr 4, 2022

@owen-d thanks for the review! I think this new feature still needs additional instrumentation, like in the shard mapper. Hope it's ok to do that in a separate PR.

Copy link
Contributor

@jeschkies jeschkies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I'm half way through the mapper. Need to go once more through it.

pkg/logql/rangemapper.go Outdated Show resolved Hide resolved
pkg/logql/rangemapper.go Outdated Show resolved Hide resolved
pkg/logql/rangemapper.go Show resolved Hide resolved
pkg/logql/rangemapper.go Outdated Show resolved Hide resolved
pkg/logql/rangemapper.go Outdated Show resolved Hide resolved
}

switch res.Data.Type() {
case parser.ValueTypeMatrix:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also parse the query each time. That's probably not as bad. In any case it feels these middlewares could be refactored at some point and "just" pass down the modified query or query plan.

pkg/querier/queryrange/split_by_range.go Show resolved Hide resolved
@chaudum chaudum force-pushed the instant-query-splitting-v3-optimizations branch from 83a67d4 to 43bdf55 Compare April 5, 2022 08:07

// Non-splittable vector aggregators
// TODO: Fix topk
//{`topk(2, count_over_time({a=~".+"}[2s]))`, time.Second},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see some successful topk.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it in a 2nd iteration :)

Copy link
Contributor

@cyriltovena cyriltovena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ship it 🚀

Copy link
Collaborator

@trevorwhitney trevorwhitney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that was a lesson in LogQL. Very cool stuff, excited for how this will improve our queries. Just a couple nits for you as that's about all I could contribute to this already impressive effort. Nice work!

}

var downstreams *ConcatSampleExpr
for interval = 0; interval < splitCount; interval++ {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super small nit: interval is a bit confusing here since it's an iterator while rangeInterval and m.splitByInterval are both durations. Maybe call this split, since it's an iterator across the splits in the splitCount?

for _, tc := range []struct {
expr string
expected string
expectNoop bool
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this test is massive. I think we could move all the noop cases to their own test for ease of finding them / organizational sake, which means we could get rid of this property in the struct. WDYT?


// clone returns a copy of the given sample expression
// This is needed whenever we want to modify the existing query tree.
func clone(expr syntax.SampleExpr) (syntax.SampleExpr, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not syntax.Clone(expr)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax.Clone() does basically the same thing, but with different types: Expr->Expr, whereas here I want SampleExpr->SampleExpr. This is mainly for convenience.

ssncferreira and others added 3 commits April 7, 2022 20:50
Co-authored-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
ssncferreira and others added 24 commits April 7, 2022 20:50
if the outer query range contains an offset as well.

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Since this is the main function of the mapper, we can ensure here that
only supported vector/range aggregations are handled.

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
…sent

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
This test is essentially the same as the test
Test_SplitRangeVectorMapping, just using a different representation of
the result.

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
… is present

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
…rouping is present

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
to have the test for noop queries separated

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
@chaudum chaudum force-pushed the instant-query-splitting-v3-optimizations branch from 699c354 to 8267d00 Compare April 7, 2022 18:51
@chaudum
Copy link
Contributor

chaudum commented Apr 7, 2022

Hey @owen-d I think we are ready to merge this PR. When you squash the commits, please feel free to remove all the "intermediate" commit messages from the individual commits, and use the PR description instead.

@owen-d owen-d merged commit 0bce8d9 into main Apr 7, 2022
@owen-d owen-d deleted the instant-query-splitting-v3-optimizations branch April 7, 2022 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants