Skip to content

CountSketch: OTLP export and sketch serialization - #77

Merged
zzylol merged 4 commits into
mainfrom
countsketch_integration
Mar 25, 2026
Merged

zzylol merged 4 commits into
mainfrom
countsketch_integration

Conversation

@GnaneshGnani

@GnaneshGnani GnaneshGnani commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Changes

  1. Code changes

    • Added OTLP sketch payload export behavior for CountSketch output flow.
    • Switched CountSketch sketch payload emission to a portable protobuf envelope in the CountSketch processor.
    • Updated processor:
      • processor/countsketchprocessor/processor.go
  2. Implementation pattern used in the processor

    • Build sketch state using sketchlib.
    • Convert sketch to a portable envelope using SerializePortable().
    • Encode the envelope with proto.Marshal(env).
    • Attach encoded bytes into OTLP metric attributes for Sketch Payload Flow.
    • Keep Raw Metrics Flow behavior (raw metric forwarding) unchanged unless the selected mode intentionally emits sketch-only output.
  3. Go module file changes

    • Updated CountSketch processor-local module file:
      • processor/countsketchprocessor/go.mod
  4. OTLP exporter compatibility settings

    • encoding: proto
    • compression: gzip or none

Compression notes

  • gzip is supported in both flows and is currently configured in CountSketch test configs for both Raw Metrics Flow and Sketch Payload Flow.
  • gzip is recommended for sketch-heavy Sketch Payload Flow traffic.
  • none is supported and useful for debugging payload size behavior, but it can hit request size limits more easily depending on environment limits.

OTLP message shape

Common wire format (both flows):

  • OTLP HTTP endpoint: POST /v1/metrics
  • OTLP gRPC service/method: opentelemetry.proto.collector.metrics.v1.MetricsService/Export
  • Body: Protobuf ExportMetricsServiceRequest
  • Optional HTTP compression: gzip (or none)

gRPC transport notes

  • gRPC uses the same ExportMetricsServiceRequest message as HTTP.
  • There is no HTTP path like /v1/metrics in gRPC; the RPC method is MetricsService.Export.
  • In local runs in this integration, gRPC receiver is typically on :4317 and HTTP receiver on :4318.
  • Message shape inside the payload is identical across HTTP and gRPC (same resource_metrics -> scope_metrics -> metrics -> data_points structure).

Shared top-level structure:

ExportMetricsServiceRequest {
    resource_metrics: [
        {
            resource: { attributes: [...] },
            scope_metrics: [
                {
                    scope: { name, version, attributes[...] },
                    metrics: [ ... ]
                }
            ]
        }
    ]
}

Raw Metrics Flow message shape

In this flow, data points carry numeric values directly (gauge or sum).

How ASAPQuery treats it:

  • No sketch payload attribute is present.
  • Points are parsed as regular metrics and routed as Raw Metrics Flow.

Sketch Payload Flow message shape (CountSketch)

In this flow, processor attaches serialized sketch bytes into OTLP attributes.
Sketch bytes are produced as:

  1. SerializePortable()
  2. proto.Marshal(...)
  3. store resulting bytes in a sketch payload attribute

Expected sketch payload attribute key in this PR:

  • countsketch.sketch_payload

How ASAPQuery treats it:

  • If countsketch.sketch_payload is present, the point is classified as Sketch Payload Flow.
  • Payload bytes are logged and processed as sketch data, not as a regular raw numeric point.

How to test these changes

1) Start ASAPQuery OTLP receiver

From ASAPQuery/:

cd ASAPQuery
RUST_LOG=query_engine_rust=debug ./target/release/query_engine_rust \
    --enable-otel-ingest \
    --otel-grpc-port 4317 \
    --otel-http-port 4318 \
    --kafka-topic dummy \
    --input-format json \
    --config asap-query-engine/examples/promql/inference_config.yaml \
    --streaming-config asap-query-engine/examples/promql/streaming_config.yaml \
    --streaming-engine arroyo \
    --prometheus-scrape-interval 15 \
    --output-dir /tmp/asapquery \
    --query-language promql \
    --lock-strategy global

Expected startup logs include OTLP listeners on :4317 (gRPC) and :4318 (HTTP).

2) Run CountSketch processor config

From DataCollector/opentelemetry-collector-contrib-patch/:

Raw Metrics Flow:

./cmd/countsketchcol/dist/countsketchcol --config cmd/countsketchcol/asap_query_config/config-otlp-pathway1.yaml

Sketch Payload Flow (batch):

./cmd/countsketchcol/dist/countsketchcol --config cmd/countsketchcol/asap_query_config/config-otlp-pathway2-batch.yaml

3) Run load generator

From DataCollector/otel_collector_benchmark/:

cd ProjectASAP/DataCollector/otel_collector_benchmark
go run main.go --endpoint localhost:53217 --workers 2 --hosts 5 --metrics 10 --duration 15s

Notes:

  • Use localhost:53217 when the processor otlp receiver gRPC endpoint is 0.0.0.0:53217.
  • For HTTP load into processor receiver, use the matching HTTP endpoint and sender tooling.

@GnaneshGnani GnaneshGnani changed the title Update CountSketch processor sketch serialization CountSketch: OTLP export and sketch serialization Mar 24, 2026
@GnaneshGnani
GnaneshGnani requested a review from zzylol March 24, 2026 04:22
@GnaneshGnani GnaneshGnani linked an issue Mar 24, 2026 that may be closed by this pull request
5 tasks
@GnaneshGnani
GnaneshGnani requested a review from zzylol March 25, 2026 00:03
@zzylol
zzylol merged commit e85a1cf into main Mar 25, 2026
@zzylol
zzylol deleted the countsketch_integration branch March 25, 2026 10:42
SieDeta pushed a commit that referenced this pull request Apr 17, 2026
* Update CountSketch processor sketch serialization

* Restore CountSketch non-serialization logic

* rename pathway references
zzylol added a commit that referenced this pull request Jul 17, 2026
Wires the GOS-aware sampled primitives (sketchlib-go #77:
UpdateStringSampledPerRowGOS/UpdateStringAtRowsGOS for CountSketch,
InsertWithHashSampledPerRowGOS/InsertWithHashAtRowsGOS for CMS) into the
ASAPCollector wrapper layer, closing the gap #518's sampling stack would
otherwise reopen: before this, a sampled insert returned before ever
reaching the GOS threshold check, so a CountSketch/CMS with both
sample_p<1 (or SDK row-admission) AND gos_delta_epsilon>0 silently lost
insert-time detection for every sampled sample — no crash, estimates stayed
unbiased, but the GOS mechanism itself never fired for that sketch.

Scope: only the collector-side wrapper composition (this PR). The SDK-side
machinery that DECIDES admittedRows/sampleP and gets them onto the wire
(aggregationrouter.go, policyfingerprint.go, monitor engine changes, OTel Go
SDK, asap-precompute-rs) is #518's own, larger, separate concern — out of
scope here, reattaches independently once it needs these primitives.

- observation.go: RowSampled/AdmittedRows/SampleP fields on
  ObservationValue (lifted from #518, unmodified) — the wire the SDK's
  row-admission decision travels on into the collector.
- countsketch.go: UpdateString's sampler branch now calls
  UpdateStringSampledPerRowGOS when GOS is active (upgrading from the old
  whole-item Admit()+divide model to per-row NitroSketch admission, per
  #518's intent, while preserving GOS composition); heap-msgpack mode is
  still excluded (its DELTA-HEAP wire form isn't GOS-converted) via the
  same gosActive condition ComputeDeltaAgainst already checks. New
  ApplyAdmittedOccurrence method + CountSketchObserver wiring for the
  SDK-pre-decided row-admission path.
- cms.go: CMS's whole-item WithSampleP/admit() sampling already composed
  correctly with GOS (InsertWithHashGOS calls admit() internally) — no
  change needed there. New ApplyAdmittedOccurrence method (CMS had none
  before) + CMSObserver wiring for the SDK-pre-decided path, mirroring
  CountSketch's.

Test plan:
- TestCountSketch_RowSampledObserve_ComposesWithGOS /
  TestCMS_RowSampledObserve_ComposesWithGOS: drive Observe with
  RowSampled=true through both wrappers, assert the wake signal fires and
  the drained delta is non-empty — proving the SDK-row-admission path
  participates in GOS instead of silently bypassing it.
- TestCountSketch_PerRowSampler_ComposesWithGOS: a live WithSampleP
  geometric sampler still triggers GOS detection through UpdateString
  directly (the other reattached path).
- go build/go vet/go test clean in asap-precompute-go (full suite, no
  regressions) and the processor package (post restore_all.sh).

Co-Authored-By: Claude Sonnet 5 <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.

Connecting DataCollector and ASAPQuery

2 participants