-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
feat: Introduce shardable probabilistic topk for instant queries. #14243
Conversation
pkg/logql/sketch/cms.go
Outdated
width := math.Ceil(math.E / epsilon) | ||
depth := math.Ceil(math.Log(1.0 / delta)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the calculation I used when doing all of our experiments, but I can't remember if I got good results using it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured we have to stay here because this makes the matrix roughly the size of our max 10k vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jeschkies what's the point of using the sketch if we're just going to send all the labels of everything we've observed in each sharded query over the wire?
If we're doing that then we might as well just have a list of tuples, labelset + count, and remove the sketch. Or use the map approach. We'd be trading space for not having to search into the slice with the map 🤷♂️
pkg/logql/sketch/cms.go
Outdated
width := math.Ceil(math.E / epsilon) | ||
depth := math.Ceil(math.Log(1.0 / delta)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the calculation I used when doing all of our experiments, but I can't remember if I got good results using it
@cstyan you are right. My rationale was that we could first validate if the team and our users accept instant queries with a special probabilistic key word and see what the implementation looks like. Then worry about the algorithm. As for the lables I'd keep it super simple and use a min-heap with max 10k labels. As Ed explained the most prominent use case is for finding the top outliers in a high cardinality set. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit hard to review with all the other unintended commits, but I think we can proceed with this implementation. I'm not entirely following how the labels tracking and heap are wired up ATM
Also, we should either clean up and reuse or completely remove the sketch/topk.go
file as part of this PR.
|
||
// Add our metric if we haven't seen it | ||
if _, ok := v.observed[metricString]; !ok { | ||
heap.Push(v, metric) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does the heap actually exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HeapCountMinSketchVector
embeds a CountMinSketchVector
and treats the metrics array as a heap. We should look into https://grafana.com/blog/2024/04/23/the-loser-tree-data-structure-how-to-optimize-merges-and-make-your-programs-run-faster/ actually.
0a04574
to
acb7754
Compare
topk actually is. Signed-off-by: Callum Styan <[email protected]>
pkg/logql/downstream_test.go
Outdated
{ | ||
labelShards: 10, // increasing this will make the test too slow | ||
totalStreams: 1_000_000, | ||
shardedQuery: `approx_topk(100, sum by (a) (sum_over_time ({a=~".+"} | logfmt | unwrap value [1s])))`, | ||
regularQuery: `topk(100, sum by (a) (sum_over_time ({a=~".+"} | logfmt | unwrap value [1s])))`, | ||
realtiveError: 0.0015, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is one of the things that is making some these test results seem better than they would be in reality; here you've got labelShards: 10
, which means that there will only be 10 unique values for the label a
but we're doing approx_topk(100, ...)
as the query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. So this test is actually no good. What we need are 1 million unique values...
Signed-off-by: Callum Styan <[email protected]>
counters to float64 so we can get float results in queries Signed-off-by: Callum Styan <[email protected]>
…4243) Signed-off-by: Callum Styan <[email protected]> Co-authored-by: Callum Styan <[email protected]> (cherry picked from commit 7b53f20)
What this PR does / why we need it:
This change introduces a very simplified shardable topk approximation through the new vector aggregation
approx_topk
.We use a count min sketch and track all labels not just the top
k
. Since this list can grow quite large the feature is only supported for instant queries. Grouping is also not supported and should be handled by an innersum by
orsum without
even though this might not be the same behaviour astopk by
.The sharding works by turning the
approx_topk(k, inner)
query into the following expression:__count_min_sketch__
is calculated for each shard and merge on the frontend.eval_cms
iterates through the labels list and determines the count for each.topk
selects then the top items.The number of labels tracked on the querier side when evaluating
__count_min_sketch__
is limited by the heap. It does count all values but the ke-value pairs might not be known.Special notes for your reviewer:
Checklist
CONTRIBUTING.md
guide (required)feat
PRs are unlikely to be accepted unless a case can be made for the feature actually being a bug fix to existing behavior.docs/sources/setup/upgrade/_index.md
production/helm/loki/Chart.yaml
and updateproduction/helm/loki/CHANGELOG.md
andproduction/helm/loki/README.md
. Example PRdeprecated-config.yaml
anddeleted-config.yaml
files respectively in thetools/deprecated-config-checker
directory. Example PR