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

feat: Introduce shardable probabilistic topk for instant queries. #14243

Open
wants to merge 30 commits into
base: main
Choose a base branch
from

Conversation

jeschkies
Copy link
Contributor

@jeschkies jeschkies commented Sep 24, 2024

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 inner sum by or sum without even though this might not be the same behaviour as topk by.

The sharding works by turning the approx_topk(k, inner) query into the following expression:

topk(
  k,
  eval_cms(
    __count_min_sketch__(inner, shard=1) ++ __count_min_sketch__(inner, shard=2)...
  )
)

__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

  • Reviewed the CONTRIBUTING.md guide (required)
  • Documentation added
  • Tests updated
  • Title matches the required conventional commits format, see here
    • Note that Promtail is considered to be feature complete, and future development for logs collection will be in Grafana Alloy. As such, feat PRs are unlikely to be accepted unless a case can be made for the feature actually being a bug fix to existing behavior.
  • Changes that require user attention or interaction to upgrade are documented in docs/sources/setup/upgrade/_index.md
  • For Helm chart changes bump the Helm chart version in production/helm/loki/Chart.yaml and update production/helm/loki/CHANGELOG.md and production/helm/loki/README.md. Example PR
  • If the change is deprecating or removing a configuration option, update the deprecated-config.yaml and deleted-config.yaml files respectively in the tools/deprecated-config-checker directory. Example PR

Comment on lines +23 to +24
width := math.Ceil(math.E / epsilon)
depth := math.Ceil(math.Log(1.0 / delta))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

@cstyan cstyan left a 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 🤷‍♂️

Comment on lines +23 to +24
width := math.Ceil(math.E / epsilon)
depth := math.Ceil(math.Log(1.0 / delta))
Copy link
Contributor

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

@jeschkies
Copy link
Contributor Author

If we're doing that then we might as well just have a list of tuples, labelset + count, and remove the sketch.

@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.

@github-actions github-actions bot added sig/operator area/helm type/docs Issues related to technical documentation; the Docs Squad uses this label across many repositories labels Oct 1, 2024
Copy link
Contributor

@cstyan cstyan 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 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.

pkg/logql/count_min_sketch.go Show resolved Hide resolved
pkg/logql/count_min_sketch.go Show resolved Hide resolved

// Add our metric if we haven't seen it
if _, ok := v.observed[metricString]; !ok {
heap.Push(v, metric)
Copy link
Contributor

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?

Copy link
Contributor Author

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.

pkg/logql/shardmapper.go Outdated Show resolved Hide resolved
pkg/logql/count_min_sketch.go Outdated Show resolved Hide resolved
pkg/logql/count_min_sketch.go Outdated Show resolved Hide resolved
@jeschkies
Copy link
Contributor Author

It works 🎉
image

@jeschkies jeschkies marked this pull request as ready for review October 3, 2024 12:21
@jeschkies jeschkies requested review from a team as code owners October 3, 2024 12:21
@jeschkies jeschkies requested a review from cstyan October 3, 2024 12:21
topk actually is.

Signed-off-by: Callum Styan <callumstyan@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/helm size/XXL type/docs Issues related to technical documentation; the Docs Squad uses this label across many repositories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants