Skip to content

KLL Aggregator Implementation - #4

Merged
zzylol merged 5 commits into
mainfrom
kll
Dec 8, 2025
Merged

zzylol merged 5 commits into
mainfrom
kll

Conversation

@Andallfor

Copy link
Copy Markdown
Contributor

Wrapper for the KLL implementation in PrecomputeEngine. The ported files are src.go, heights.go, and kll_test.go.

See the sample.conf for usage, but briefly you define k and quantiles (0 - 1). The aggregator will then aggregate and output the desired quantiles for each numeric field in every metric.

Verification

I ported the tests from PrecomputeEngine as well, and everything should pass. I also did a manual inspection and everything seemed correct there too.

Benchmarks

Ran using benchmarks/max-throughput-prometheus-input.conf (this the same as max-throughput-prometheus-client.conf but with the socket_listener plugin replaced with the prometheus input from max-throughput-gorilla-local.conf).

Test Description Median Write/s
Base The above configuration with KLL aggregator disabled 93,200
No Write Just the wrapper with the actual KLL functionality disabled (that is, we do not give the sketch any values and do not request any quantiles, but do all the processing related to storing metrics/fields etc.). Essentially is my actual code 90,800 (-2.5%)
KLL 90,000 (-3.5%)
benchmarks

@Andallfor
Andallfor requested a review from zzylol December 8, 2025 05:19
@Andallfor Andallfor self-assigned this Dec 8, 2025
@Andallfor Andallfor linked an issue Dec 8, 2025 that may be closed by this pull request
Comment thread telegraf-patch/plugins/aggregators/kll/src.go Outdated
Comment thread backup_telegraf_patches.sh
@zzylol
zzylol merged commit 4a90177 into main Dec 8, 2025
@zzylol
zzylol deleted the kll branch December 8, 2025 18:29
@Andallfor Andallfor removed their assignment Mar 1, 2026
SieDeta pushed a commit that referenced this pull request Apr 17, 2026
KLL Aggregator Implementation
zzylol added a commit that referenced this pull request Apr 21, 2026
B3 delta / B4 tunable window)

Adds the five baselines paper §6.2 compares head-to-head. Each
baseline is one agent-pipeline YAML + one compose overlay; the
same asap/sketchcol:dev binary serves all of them — only the
mounted config + env differ.

  * B0 raw OTel (`sketchcol-agent-b0-raw.yaml`): OTLP →
    batch → OTLP. Control — no sketching, no compression.
  * B1 Serf (`…-b1-serf.yaml`): Gorilla-style XOR compression
    written to local tmpfs. Rebuild sketchcol to include
    `serfprocessor` (added to builder-config.yaml).
  * B2 full sketch (`…-b2-full.yaml`): DDSketch + HLL,
    `transmit_sketch: true, mode: batch`. Today's default.
  * B3 delta sketch (`…-b3-delta.yaml`): same sketches,
    `mode: window, window_duration: 60s,
    delta_transmission: true`. Wire payload = sparse diff
    of only-changed buckets since last flush.
  * B4 tunable window (`…-b4-tunable.yaml`): same as B3 but
    `window_duration: ${env:SKETCH_WINDOW}` — sweep 5s / 30s /
    60s / 300s without rebuilding.

Switching baselines:

  AGENT_CONFIG=sketchcol-agent-b3-delta.yaml \
    docker compose -f base.yml -f agents-N1.yml \
      -f baseline-b3-delta.yml up -d

  SKETCH_WINDOW=10s \
    AGENT_CONFIG=sketchcol-agent-b4-tunable.yaml \
    docker compose -f base.yml -f agents-N1.yml \
      -f baseline-b4-tunable.yml up -d

The `AGENT_CONFIG` env var threads through agents-N*.yml's
mounted config path. `SKETCH_WINDOW` is plumbed to every agent
by gen-agents.sh (default 60s). Baseline overlays are thin
naming markers that stamp `controller.labels.asap.baseline`;
all five coexist so a single bring-up run can identify its
baseline from `docker inspect`.

sketchcol binary rebuild required (binary bundles serfprocessor
now). Host build chain unchanged — see Dockerfile.sketchcol
header for the submodule + sketchlib-go sibling prereqs.

Live-validated B3 at N=1 after one 60s window flush:
  * DDSketch input = 1.31 GiB, output = 3.21 MiB → **408×
    bandwidth reduction** on the wire.
  * Compared to B2 (same workload, full-sketch batch mode):
    output/input ratio was 177% — B3 is ~720× smaller per
    window-flush than B2.

Follow-up before the full eval:
  * Paper §6.4 accuracy comparison between B2 and B3 needs the
    backend's sketch-reconstitution path to handle delta wire-
    format — existing `sketchlib-go` delta codec work
    (Phase 1 packed arrays) covers this.
  * `fake-exporter` could emit a more faithful Google-trace
    replay instead of synthetic log-normal — DC TODO #4.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zzylol added a commit that referenced this pull request Apr 22, 2026
First end-to-end run of all 5 baselines via the PR #178 sweep
script. Values are from the 75s soak at (rate=1000/s,
cardinality=1000) on a log-normal gauge workload:

  Baseline          CPU    RSS    Out MiB/s   × vs B0
  B0 raw OTel       0.77c  214MB  16.34       1.00×
  B1 Serf XOR       0.59c  271MB   3.44       1/ 4.8×
  B5 Gorilla XOR    0.58c  297MB   3.84       1/ 4.3×
  B2 full sketch    1.00c  506MB  163.77     10.03×    ⚠ 10× larger than raw
  B3 delta (60s)    0.45c  225MB   0.053      1/305.8×  ✓ paper's bandwidth claim

Two takeaways worth flagging:

  * B2 full-sketch is an order of magnitude WORSE than raw at
    1-second batch cadence — per-batch DDSketch+HLL state at
    cardinality=1000 dwarfs the raw gauge points it summarizes.
    This motivates why naive sketch-per-batch isn't a viable
    deployment, and why the paper needs delta + windowing.
  * B3 delta (60s) hits 305× reduction vs raw, exactly the
    bandwidth story §6.2 leads with. All four sketch families
    (DDSketch, HLL, CountSketch, CountMin) are delta-ready
    end-to-end (ASAPQuery-backend #60-#63 chain) so §6.4
    accuracy comparisons can run against reconstituted sketches.
  * B1 Serf + B5 Gorilla compression is modest (~5% and 2.4%)
    because log-normal synthetic data has poor temporal
    correlation; real trace data typically compresses much
    better. Google-cluster-trace replay (DC TODO #4) is the
    follow-up that would fix this.

Raw CSV archived for reproducibility; regenerate via:

  BASELINES="b0-raw b1-serf b2-full b3-delta b5-gorilla" \
    SCALE=N1 RATES=1000 CARDS=1000 SOAK_S=75 \
    ./deploy/scripts/run-baseline-sweep.sh > out.csv

B3's measured out-bytes takes a longer soak (≥3 min) because
of its 60s window — the sweep default of 75s yields one flush,
and the script's 1m rate() window returns NaN on a single
sample. The archived number (0.053 MiB/s) is from a separate
180s soak.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zzylol added a commit that referenced this pull request May 18, 2026
…eConfig (ASAPCollector#381 Issue #4) (#389)

Two paired fixes to close the apply-loop the smoke test surfaced
after ASAPQuery-backend PR #279 landed:

(1) No-op short-circuit in processRemoteConfig

Before writing the pushed body to disk + exiting, compare to the
current on-disk file. If they match byte-for-byte, just report
APPLIED and return — don't restart. This handles two scenarios:

  * Defense-in-depth against a controller resending the same
    config (which can happen any time the OpAMP server's
    LastRemoteConfigHash cache is empty or stale — e.g. on
    reconnect before the agent has reported APPLIED).
  * The deterministic-emit guarantee from ASAPQuery-backend #281
    means same-semantic-content → same bytes, so this check is
    accurate for the controller's emit.

(2) Advertise ReportsRemoteConfig capability

In addition to AcceptsRemoteConfig, set
`AgentCapabilities_AgentCapabilities_ReportsRemoteConfig` when
`remote_config_path` is configured. Without this bit,
`opampClient.SetRemoteConfigStatus(APPLIED)` returns
`ErrReportsRemoteConfigNotSet` (opamp-go
client/internal/clientcommon.go:21), the client lib refuses to
record the applied hash, and the server has no way to learn the
config was processed — keeping it stuck in the resend loop. Both
bits are needed for the full feedback cycle.

End-to-end smoke (post-#281 deterministic emit + this PR):
  * Agent boots from bootstrap YAML
  * Receives RemoteConfig push, bytes differ, applies + exits
  * Restarts, loads new YAML
  * Receives RemoteConfig push, bytes IDENTICAL (deterministic emit)
  * No-op short-circuit fires → SetRemoteConfigStatus(APPLIED) →
    keeps running, no more restarts
  * Pipeline emits sketches normally; smoke test Axis D registers
    them

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

KLL in telegraf aggreagtor

2 participants