Repository navigation
Compare sketch, exact and store-and-query in the cardinality demo as traffic grows - #41
Merged
Merged
Conversation
zzylol
force-pushed
the
feat/topk-tradeoff-demo
branch
from
October 20, 2026 23:38
70db4c0 to
f4c1d28
Compare
zzylol
force-pushed
the
feat/cardinality-tradeoff-demo
branch
2 times, most recently
from
October 20, 2026 23:38
ba4d60b to
fc4afc4
Compare
zzylol
force-pushed
the
feat/topk-tradeoff-demo
branch
from
October 20, 2026 23:38
f4c1d28 to
21506c7
Compare
zzylol
force-pushed
the
feat/cardinality-tradeoff-demo
branch
from
October 20, 2026 23:39
fc4afc4 to
d997227
Compare
zzylol
force-pushed
the
feat/topk-tradeoff-demo
branch
from
October 20, 2026 23:39
21506c7 to
0fdc065
Compare
…traffic grows The cardinality scenario now follows the top-k ladder: the rate per source doubles every 5 minutes (5k to 80k points/s), and at minute 10 http.route explodes from 20 to 20,000 values. The query job answers the store-and-query baseline with one LogQL distinct count per attribute key over loki-raw and reports failed queries; loki-raw allows enough series for every user.id of a window. With each raw answer the query job republishes the sketch and exact answers of the same window, so the top-k and cardinality tables compare the three approaches on one window although store and query answers later. The cardinality dashboard shows the three approaches side by side per key with their error against exact and each detector's class, error over time, traffic volume and shape, the freshness breakdown and per-approach resources. Acceptance checks store and query against exact. Throughput panels read each pipeline's last per-window count within 2 minutes, so a stalled pipeline shows a gap, and say that raw counts are the points loki-raw acknowledged within 50 s of the window's end.
zzylol
force-pushed
the
feat/cardinality-tradeoff-demo
branch
from
October 20, 2026 23:55
d997227 to
2eebd74
Compare
…current Acceptance removed every ramp line from the cardinality generators but left an empty changes key, which reads as null and stops the generators; it now drops the key too, and the store-and-query check requires every key exact counted. The query job publishes the comparison gauges without a timestamp, with the compared window's end, so the tables stay filled however far store and query lags; an empty LogQL result counts as a refused query, and the keys come from exact's answer. The error panels only compare samples of the same window. The dashboard generator is now in the repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The cardinality demo compared the HLL sketch with exact counting at one fixed rate. Like the top-k demo before #40, it did not show the obvious alternative: store every raw point and count distinct values in the store when asked. It also could not show how each approach behaves as traffic grows or when an attribute's cardinality suddenly explodes, which is when a log store's distinct-count query gets expensive.
What
The cardinality dashboard (
/d/asap-cardinality) now compares the same three approaches as the top-k demo:method="raw"): the query job counts the distinct values of each attribute key inloki-rawwith one LogQL query per key and reports them (asap_distinct{method="raw"}). A query Loki refuses (for example over its series limit) is reported asasap_query_failed.http.routeexplodes from 20 to 20,000 values (as when an ID leaks into the route).user.idstays unique per point andk8s.pod.namekeeps growing 5%/min.How
query_job.py: a raw answer per use case. Cardinality runscount(sum by (<key>) (count_over_time({service_name="checkout"}[60s])))for each key exact counted, at the window's last millisecond; the backend query time is the sum over keys, including refused queries. A refused, timed-out or empty query is reported asasap_query_failed, never as 0. With each raw answer it republishes the sketch and exact distinct counts and classes of the same window (asap_compare_distinct,asap_compare_class,asap_compare_failed) and that window's end (asap_compare_window_end). These carry no timestamp, so the tables always show the latest compared window, however far store and query lags. The Prometheus answer query it times is now the use case's own answer metric.loki-raw: up to 20,000,000 series per query. Loki still refuses theuser.iddistinct count (HTTP 413) from about 2.4 million values per window.grafana/gen_dashboards.py(now in the repository). The tables carry a panel naming the compared window and, for cardinality, a "refused" column; the error-over-time panels only compare samples of the same window; the throughput panels read each pipeline's last count within 2 minutes, so a stalled pipeline shows a gap, and say that raw counts are the pointsloki-rawacknowledged within 50 s of the window's end.loki-rawwithin 1% of exact, on the latest window in which it answered them all. The scaled copy drops achanges:key left empty after the ramp lines are removed (it would read as null)..gitignoreignores__pycache__/.Before
http.routecardinality.After
Measured on the demo machine over the 30-minute ladder (2 sources, 1-minute windows;
user.idis unique per point, so its distinct count equals the window's points):user.idper windowuser.idquery refused by Loki (HTTP 413); other keys exact; about 63 sloki-rawkeeps about 50% of the points;user.idrefusedencodingfailures)loki-rawkeeps about 27%; no distinct countshttp.routefrom stable to growing in the same window (20 → 19,989 values; the sketch estimates 19,749, −1.2%), and back to stable once the 10-window baseline has absorbed it.loki-raw).loki-rawpeaks at 1.7 GiB.Verification
python3 -m py_compileon the changed scripts; no Rust changes in this PR. CI runs the scaled acceptance, including the new check.changes:in the scaled cardinality configs, every key required in the acceptance check, unstamped comparison gauges, same-window error panels, empty results as refused, the Loki comment, and the generator in the repository. The fixed query job and dashboards were checked against the running demo.