Skip to content

feat: add OTel observability benchmark demo - #2

Draft
Ladas wants to merge 5 commits into
praxis-proxy:mainfrom
Ladas:feat/otel-benchmark-demo
Draft

feat: add OTel observability benchmark demo#2
Ladas wants to merge 5 commits into
praxis-proxy:mainfrom
Ladas:feat/otel-benchmark-demo

Conversation

@Ladas

@Ladas Ladas commented Aug 14, 2026

Copy link
Copy Markdown

Summary

  • Add extraPortMappings support to ClusterSpec for macOS KIND port forwarding
  • Add full OTel observability benchmark demo with composable stacks
  • Both scenarios with A/B/C benchmarks (baseline vs OTel noop vs OTel full export)

Stack deployed by forge up

Prometheus + Grafana 11.x, Tempo, Loki + Promtail, OTel Collector, MLflow, Fortio echo, inference-sim, Praxis proxy (OTel-enabled)

Quick start

See examples/otel-benchmark/README.md for full instructions.

Dashboards

Dashboard Description
Proxy Overview Request rate, latency P50/P99, requests by method
OTel Traces Searchable trace table with clickable Trace IDs
Benchmark Results CPU/memory for praxis + collector, RPS under load
AI/LLM Golden Signals P95 latency, throughput, future AI token metrics
Structured Logs Loki log volume + praxis access log entries

Benchmark Results (2026-08-14)

Scenario 1: Core Praxis OTel Overhead

Platform: KIND (1 node, macOS arm64) | Backend: Fortio echo | Rate: 2000 RPS x 30s x 3 runs
10 spans per request (root + 8 per-filter + upstream_exchange).

Config P50 (us) P99 (us) RPS P50 delta P99 delta
Baseline (praxis:dev) 389 617 2000 -- --
OTel noop (praxis:dev-otel) 383 670 1999 -1.5% +8.6%
OTel full (praxis:dev-otel + export) 422 820 2000 +8.5% +32.9%

Scenario 2: AI Praxis with Inference Sim

Platform: KIND (1 node, macOS arm64) | Backend: inference-sim (mock LLM) | Rate: 500 RPS x 30s x 3 runs
11 spans per request (core spans + response_body phase).

Config P50 (us) P99 (us) RPS P50 delta P99 delta
AI Baseline (praxis-ai:dev) 728 1528 500 -- --
AI OTel noop (praxis-ai:dev-otel) 592 8903 500 -18.7% +482.7%
AI OTel full (praxis-ai:dev-otel + export) 528 1541 500 -27.5% +0.9%

Note: AI OTel images are built from a different code branch with performance improvements in the OTel code path, which explains the P50 decrease. The noop P99 spike reflects first-run warmup.

AI Span Tree

POST /v1/chat/completions -> inference-sim  (root)
  |-- filter:request_id:request
  |-- filter:access_log:request
  |-- filter:router:request        -> routes /v1/* to inference cluster
  |-- filter:load_balancer:request
  |-- filter:load_balancer:response
  |-- filter:router:response
  |-- filter:access_log:response
  |-- filter:request_id:response
  |-- filter:access_log:response_body
  +-- upstream_exchange [inference-sim:8000]

Dependencies (unmerged PRs)

Build requires cherry-picking these OTel PRs onto praxis main:

PR Description
praxis#956 TCP lifecycle spans
praxis#957 trace_context filter
praxis#958 upstream spans
praxis#959 span events
praxis#960 access log trace ID
praxis#970 semconv followup
praxis#982 Tokio runtime fix for OTel batch exporter
praxis#983 per-filter child spans
ai#751 OTel tracing export fix

Ladas added 5 commits August 15, 2026 10:48
Extend ClusterSpec with a ports field (reusing PortMapping) that renders
as extraPortMappings in the KIND cluster config. Required for macOS
where MetalLB LoadBalancer IPs are unreachable from the host.

Port mappings are applied to the first control-plane node. Validation
rejects zero ports and duplicate host port bindings.

Signed-off-by: Ladislav Smola <lsmola@redhat.com>
Add composable OTel benchmark example with:
- examples/stacks/observability/ (shared OTel Collector + dashboards)
- examples/stacks/mock-backends/ (Fortio echo + inference-sim)
- examples/otel-benchmark/ (forge.yaml, configs, scripts, README)

Deploys Prometheus, Grafana, Tempo, Loki, OTel Collector, MLflow,
and Praxis proxy on KIND. Includes A/B/C benchmark scripts for
measuring OTel tracing overhead.

Signed-off-by: Ladislav Smola <lsmola@redhat.com>
- Add Scenario 2: AI benchmark with inference-sim (POST /v1/chat/completions)
  - benchmark-ai.sh: A/B/C comparison at 500 RPS (baseline/noop/full)
  - report-ai.sh: generate markdown report from AI benchmark results
  - ai-otel-full.yaml: config with /v1/* -> inference, / -> echo routing
- Fix OTel collector: remove broken MLflow exporter (protobuf vs JSON mismatch)
- Fix MLflow helm: enable databaseMigration, set service.type=NodePort
- Fix praxis manifest: correct ENTRYPOINT comment for AI vs core images
- Update README with both scenarios, span tree, build instructions

Signed-off-by: Ladislav Smola <lsmola@redhat.com>
…orkflow

Signed-off-by: Ladislav Smola <lsmola@redhat.com>
- Add access_log filter to baseline and otel-noop configs so all three
  core benchmark runs use identical filter chains (4 filters, 10 spans)
- Create ai-baseline.yaml and ai-otel-noop.yaml for per-run config
  isolation in the AI benchmark (prevents noop from exporting via
  hardcoded otlp_endpoint in ai-otel-full.yaml)
- Update benchmark-ai.sh to use per-run config files
- Fix README dashboard titles to match actual Grafana JSON titles
- Fix Known Issues: collector exports to Tempo only, not MLflow
- Fix otel-collector stack description (remove "+ MLflow")
- Fix praxis.yaml stale comments (setup.sh reference, phantom args)
- Add labels to Service metadata so ServiceMonitor selector matches
- Pin mock backend images (fortio:1.75.2, inference-sim:v0.10.2)

Signed-off-by: Ladislav Smola <lsmola@redhat.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.

1 participant