mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 06:10:58 +00:00
Three doc conflicts, all inside Phase 10's own sections. Resolved by keeping phase-9's corrections and re-applying phase-10's ownership of those sections on top, rather than taking either side wholesale: 06 §6.8.3 — Status now says Phase 10 is implemented on THIS branch (phase-9's copy said "not merged into this branch", true there, false here). The stale "71 checks" enumeration and "Current Status" list are replaced by phase-9's dynamic-count description plus a Known Gaps list that states the real reason the rpc.process hierarchy is unassertable: rpc.process is HTTP-only, so a WebSocket-only workload never produces it. Phase-9's CI Deliverable subsection is carried through; exit criteria keep phase-10's tick state with phase-9's corrected wording. 06 §6.8.3 Architecture — the automatic merge had resurrected phase-10's stale 2-node cluster prose and diagram over phase-9's 5-node correction. Reconciled to phase-10's topology (native xrpld processes vs the containerised backend, which is accurate) with phase-9's node count: 5 validators, and the collector labelled OTLP + filelog rather than StatsD, which the config has never had. Dropped the "all 26 metrics required" label in favour of the manifest. 06 §6.8.3 Key Implementation Details — two claims corrected against the code. The StatsD m_dirty gauge fix describes a member that exists nowhere in the repo, and the harness sets [insight] server=otel anyway, so gauges export through an observable-gauge callback. The tx.receive attribute keys are bare suppressed and tx_status, not dotted, and tx_status is set only on the reject/known-bad/dropped paths, so it is absent on a successful receive. 09 §5c — kept phase-10's four-column table shape, with phase-9's corrected counts: 40 of 41 emitted spans, 67 required attributes, 14 of 15 dashboards. Phase10_taskList — dynamic inventory totals, the real RPC span trees, and exit criteria ticked where the code on this branch closes them. Per-RPC timings are recorded as not gated: regression-metrics.json defines only spans and job_queue. Verified every hunk of the phase-10 diff falls inside a Phase-10-owned section (06 §6.8.3, 09 §5c, Phase10_taskList, and the runbook's appended Phase 10 sections); no phase-9-owned text is modified from this branch.
309 lines
14 KiB
Markdown
309 lines
14 KiB
Markdown
# Phase 10: Synthetic Workload Generation & Telemetry Validation — Task List
|
|
|
|
> **Status**: Future Enhancement
|
|
>
|
|
> **Goal**: Build tools that generate realistic XRPL traffic to validate the full Phases 1-9 telemetry stack end-to-end — all spans, attributes, metrics, dashboards, and log-trace correlation — under controlled load.
|
|
>
|
|
> **Scope**: Python/shell test harness + multi-node docker-compose environment + automated validation scripts + performance benchmarks.
|
|
>
|
|
> **Branch**: `pratik/otel-phase10-workload-validation` (from `pratik/otel-phase9-metric-gap-fill`)
|
|
>
|
|
> **Depends on**: Phase 9 (internal metric gap fill) — validates the full metric surface
|
|
|
|
### Related Plan Documents
|
|
|
|
| Document | Relevance |
|
|
| -------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
| [06-implementation-phases.md](./06-implementation-phases.md) | Phase 10 plan: motivation, architecture, exit criteria (§6.8.3) |
|
|
| [09-data-collection-reference.md](./09-data-collection-reference.md) | Defines the full inventory of spans/metrics to validate |
|
|
| [Phase9_taskList.md](./Phase9_taskList.md) | Prerequisite — all internal metrics must be emitting |
|
|
|
|
### Why This Phase Exists
|
|
|
|
Before Phases 1-9 can be considered production-ready, we need proof that:
|
|
|
|
1. Every emitted span fires with its required attributes under real transaction
|
|
workloads — the harness derives the span and attribute totals from
|
|
`expected_spans.json`, so no fixed "16 spans / 22 attributes" figure applies
|
|
2. All 255+ StatsD metrics + ~50 Phase 9 metrics appear in Prometheus with non-zero values
|
|
3. Log-trace correlation (Phase 8) produces clickable trace_id links in Loki
|
|
4. The 14 harness-asserted Grafana dashboards render meaningful data (no empty
|
|
panels); 15 are on disk
|
|
5. Performance overhead stays within bounds (< 3% CPU, < 5MB memory)
|
|
6. The telemetry stack survives sustained load without data loss or queue backpressure
|
|
|
|
---
|
|
|
|
## Task 10.1: Multi-Node Test Harness
|
|
|
|
**Objective**: Create a docker-compose environment with 3-5 validator nodes that produces real consensus rounds.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/docker-compose.workload.yaml` — **as shipped this file
|
|
holds only the observability backend**: `otel-collector`, `tempo`,
|
|
`prometheus`, `loki`, `grafana`. It contains **no xrpld services**.
|
|
- Shared network (`workload-net`) with service discovery
|
|
|
|
- The 5 validators are **native `xrpld` processes**, not containers.
|
|
`docker/telemetry/workload/run-full-validation.sh` (`NUM_NODES=5`) generates
|
|
keys, writes a per-node `xrpld.cfg`, and launches each node on
|
|
`127.0.0.1` with sequential RPC / WS / peer ports. Each node:
|
|
- Gets its validator key from `generate-validator-keys.sh`
|
|
- Lists the other 4 nodes in `ips_fixed`
|
|
- Has all telemetry enabled: `[telemetry] enabled=1`, `[insight] server=otel`
|
|
- Enables all trace categories including `trace_peer=1`
|
|
- Writes logs to a file tailed by the OTel Collector filelog receiver
|
|
|
|
- ❌ **`make telemetry-workload-up` / `make telemetry-workload-down` were never
|
|
implemented.** There is no `Makefile` anywhere in the repository. The entry
|
|
point is `run-full-validation.sh` (with `--profile`, `--nodes`,
|
|
`--skip-loki`, `--skip-regression`, `--with-benchmark`). The node-count flag is
|
|
spelled `--nodes`, **not** `--num-nodes` — `run-full-validation.sh:80` (usage)
|
|
and `:100` (the `case` arm). `NUM_NODES` is the internal shell variable it
|
|
assigns to.
|
|
|
|
**Key files**:
|
|
|
|
- New: `docker/telemetry/docker-compose.workload.yaml` (backend only)
|
|
- New: `docker/telemetry/workload/generate-validator-keys.sh`
|
|
- New: `docker/telemetry/workload/run-full-validation.sh` — writes each node's
|
|
cfg **inline** via a heredoc at `run-full-validation.sh:242`
|
|
(`cat >"$NODE_DIR/xrpld.cfg" <<EOCFG`)
|
|
- New: `docker/telemetry/workload/xrpld-validator.cfg.template` (96 lines) — it
|
|
**was** created and is tracked on the Phase 10 branch, but it is **unused**:
|
|
nothing reads it, and its `{{NODE_INDEX}}` / `{{RPC_PORT}}` / `{{OTEL_ENDPOINT}}`
|
|
placeholders are never substituted, because the inline heredoc above supersedes
|
|
it. Either wire the script to the template or delete the template — keeping both
|
|
guarantees they drift.
|
|
|
|
---
|
|
|
|
## Task 10.2: RPC Load Generator
|
|
|
|
**Objective**: Configurable tool that fires all traced RPC commands at controlled rates.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/workload/rpc_load_generator.py`:
|
|
- Connects to one or more xrpld WebSocket endpoints
|
|
- Fires all RPC commands that have trace spans: `server_info`, `ledger`, `tx`, `account_info`, `account_lines`, `fee`, `submit`, etc.
|
|
- Configurable parameters: rate (RPS), duration, command distribution weights
|
|
- Injects `traceparent` HTTP headers to test W3C context propagation
|
|
- Logs progress and errors to stdout
|
|
|
|
- Command distribution should match realistic production ratios:
|
|
- 40% `server_info` / `fee` (health checks)
|
|
- 30% `account_info` / `account_lines` / `account_objects` (wallet queries)
|
|
- 15% `ledger` / `ledger_data` (explorer queries)
|
|
- 10% `tx` / `account_tx` (transaction lookups)
|
|
- 5% `book_offers` / `amm_info` (DEX queries)
|
|
|
|
**Key files**:
|
|
|
|
- New: `docker/telemetry/workload/rpc_load_generator.py`
|
|
- New: `docker/telemetry/workload/requirements.txt`
|
|
|
|
---
|
|
|
|
## Task 10.3: Transaction Submitter
|
|
|
|
**Objective**: Generate diverse transaction types to exercise `tx.*` and `ledger.*` spans.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/workload/tx_submitter.py`:
|
|
- Pre-funds test accounts from genesis account
|
|
- Submits a mix of transaction types:
|
|
- `Payment` (XRP and issued currencies) — exercises `tx.process`, `tx.apply`
|
|
- `OfferCreate` / `OfferCancel` — DEX activity
|
|
- `TrustSet` — trust line creation for issued currencies
|
|
- `NFTokenMint` / `NFTokenCreateOffer` / `NFTokenAcceptOffer` — NFT activity
|
|
- `EscrowCreate` / `EscrowFinish` — escrow lifecycle
|
|
- `AMMCreate` / `AMMDeposit` / `AMMWithdraw` — AMM pool operations (if amendment enabled)
|
|
- Configurable: TPS target, transaction mix weights, duration
|
|
- Monitors submission results and tracks success/failure rates
|
|
|
|
- The transaction mix ensures the telemetry captures the full range of ledger activity that third parties care about.
|
|
|
|
**Key files**:
|
|
|
|
- New: `docker/telemetry/workload/tx_submitter.py`
|
|
- New: `docker/telemetry/workload/test_accounts.json` (pre-generated keypairs)
|
|
|
|
---
|
|
|
|
## Task 10.4: Telemetry Validation Suite
|
|
|
|
**Objective**: Automated scripts that verify all expected telemetry data exists after a workload run.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/workload/validate_telemetry.py`:
|
|
|
|
**Span validation** (queries Tempo API):
|
|
- Assert every required span name in `expected_spans.json` appears in traces.
|
|
Conditional spans — `grpc.*`, `ledger.acquire`, `txq.*`,
|
|
`consensus.mode_change`, `rpc.process` — are marked `optional` and skipped
|
|
when the workload does not exercise them.
|
|
- Assert each span has its required attributes (bare/underscore keys; dotted
|
|
`xrpl.*` is reserved for resource attributes)
|
|
- Assert parent-child relationships are correct. The two live RPC trees are:
|
|
- HTTP: `rpc.http_request` -> `rpc.process` -> `rpc.command.*`
|
|
- WebSocket: `rpc.ws_message` -> `rpc.command.*` — **there is no
|
|
`rpc.process` on the WS path**. `rpc.process` is created only in
|
|
`ServerHandler::processRequest()` (`ServerHandler.cpp:705`), reached from
|
|
`processSession(Session, coro)`, i.e. HTTP only. Under WS-only load
|
|
`rpc.process` never appears, and `rpc.command.*` parents directly to
|
|
`rpc.ws_message`.
|
|
- Assert span durations are reasonable (> 0, < 60s)
|
|
|
|
**Metric validation** (queries Prometheus API):
|
|
- Assert all SpanMetrics-derived metrics are non-zero: `span_calls_total`,
|
|
`span_duration_milliseconds_bucket` (the connector's `namespace` is `span`,
|
|
not `traces_span_metrics` — `otel-collector-config.yaml:113-114`)
|
|
- Assert the insight-sourced metrics are non-zero: `ledgermaster_validated_ledger_age`,
|
|
`peer_finder_active_{inbound,outbound}_peers`, etc. — all lowercase, no
|
|
`xrpld_` prefix (`77f35c03db` removed the prefix and lowercased names)
|
|
- Assert all Phase 9 metrics are non-zero: `nodestore_state`, `cache_metrics`,
|
|
`txq_metrics`, `rpc_method_{started,finished,errored}_total`, `object_count`,
|
|
`load_factor_metrics`
|
|
- Assert metric label cardinality is within bounds
|
|
|
|
**Log-trace correlation validation** (queries Loki API):
|
|
- Assert logs contain `trace_id=` and `span_id=` fields
|
|
- Pick a random trace_id from Tempo → query Loki for matching logs → assert results exist
|
|
- Assert Grafana derived field links are functional
|
|
|
|
**Dashboard validation**:
|
|
- For each dashboard, query the dashboard API and assert no panels show "No
|
|
data". There are **15 dashboards on disk**; the harness asserts **14** —
|
|
`log-derived-insights` is provisioned but unasserted.
|
|
|
|
- Output: JSON report with pass/fail per check, suitable for CI.
|
|
|
|
**Key files**:
|
|
|
|
- New: `docker/telemetry/workload/validate_telemetry.py`
|
|
- New: `docker/telemetry/workload/expected_spans.json` (span inventory for validation)
|
|
- New: `docker/telemetry/workload/expected_metrics.json` (metric inventory for validation)
|
|
|
|
---
|
|
|
|
## Task 10.5: Performance Benchmark Suite
|
|
|
|
**Objective**: Measure CPU/memory/latency overhead of the telemetry stack.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/workload/benchmark.sh`:
|
|
- **Baseline run**: Start cluster with `[telemetry] enabled=0`, run transaction workload for 5 minutes, record metrics
|
|
- **Telemetry run**: Start cluster with full telemetry enabled, run identical workload, record metrics
|
|
- **Comparison**: Calculate deltas for:
|
|
- CPU usage (per-node average)
|
|
- Memory RSS (per-node peak)
|
|
- RPC p99 latency
|
|
- Transaction throughput (TPS)
|
|
- Consensus round time p95
|
|
- Ledger close time p95
|
|
|
|
- Output: Markdown table comparing baseline vs. telemetry, with pass/fail against targets:
|
|
- CPU overhead < 3%
|
|
- Memory overhead < 5MB
|
|
- RPC latency impact < 2ms p99
|
|
- Throughput impact < 5%
|
|
- Consensus impact < 1%
|
|
|
|
- Store results in `docker/telemetry/workload/benchmark-results/` for historical tracking.
|
|
|
|
**Key files**:
|
|
|
|
- New: `docker/telemetry/workload/benchmark.sh`
|
|
- New: `docker/telemetry/workload/collect_system_metrics.sh`
|
|
|
|
---
|
|
|
|
## Task 10.6: CI Integration
|
|
|
|
**Objective**: Wire the validation suite into CI for regression detection.
|
|
|
|
**What to do**:
|
|
|
|
- Create a CI workflow (GitHub Actions or equivalent) that:
|
|
1. Builds xrpld with `-DXRPL_ENABLE_TELEMETRY=ON`
|
|
2. Starts the multi-node workload harness
|
|
3. Runs the RPC load generator + transaction submitter for 2 minutes
|
|
4. Runs the validation suite
|
|
5. Runs the benchmark suite
|
|
6. Fails the build if any validation check fails or benchmark exceeds thresholds
|
|
7. Archives the validation report and benchmark results as artifacts
|
|
|
|
- This should be a separate workflow (not part of the main CI), triggered manually or on telemetry-related branch changes.
|
|
|
|
**Key files**:
|
|
|
|
- New: `.github/workflows/telemetry-validation.yml`
|
|
- New: `docker/telemetry/workload/run-full-validation.sh` (orchestrator script)
|
|
|
|
---
|
|
|
|
## Task 10.7: Documentation
|
|
|
|
**Objective**: Document the workload tools and validation process.
|
|
|
|
**What to do**:
|
|
|
|
- Create `docker/telemetry/workload/README.md`:
|
|
- Quick start guide for running workload harness
|
|
- Configuration options for load generator and tx submitter
|
|
- How to read validation reports
|
|
- How to run benchmarks and interpret results
|
|
|
|
- Update `docs/telemetry-runbook.md`:
|
|
- Add "Validating Telemetry Stack" section
|
|
- Add "Performance Benchmarking" section
|
|
|
|
- Update `OpenTelemetryPlan/09-data-collection-reference.md`:
|
|
- Add "Validation" section with expected metric/span counts
|
|
|
|
---
|
|
|
|
## Exit Criteria — Delivered in PR #6519
|
|
|
|
- [x] 5-node validator cluster starts and reaches consensus — as native `xrpld`
|
|
processes driven by `run-full-validation.sh` (`NUM_NODES=5`), not from
|
|
docker-compose
|
|
- [x] RPC load generator fires all traced RPC commands at configurable rates
|
|
- [x] Transaction submitter generates 6+ transaction types at configurable TPS
|
|
- [x] Validation suite confirms the full span / attribute / metric inventory
|
|
(totals computed dynamically from `expected_spans.json` /
|
|
`expected_metrics.json`)
|
|
- [x] Log-trace correlation validated end-to-end (Loki <-> Tempo) — implemented
|
|
and passing locally, but CI runs with `--skip-loki`, so it is not gated
|
|
- [x] All 14 harness-asserted Grafana dashboards render data (no empty panels);
|
|
15 on disk, `log-derived-insights` unasserted
|
|
- [x] Overhead benchmark (`benchmark.sh`) measures telemetry-off vs telemetry-on
|
|
deltas
|
|
- [ ] Benchmark shows < 3% CPU overhead, < 5MB memory overhead — needs a
|
|
measured run
|
|
- [x] CI workflow runs validation on telemetry branch changes
|
|
- [x] Validation report output is CI-parseable (JSON with exit codes)
|
|
- [x] OTel-driven regression gate captures per-span and per-job timings from
|
|
Prometheus and compares against a committed baseline. Per-RPC timings are
|
|
**not** gated: `regression-metrics.json` defines only `spans` and
|
|
`job_queue` groups (FU-4).
|
|
|
|
## Follow-up Work (tracked in separate PRs)
|
|
|
|
- [ ] FU-2: Automate baseline persistence across CI runs (artifact uploaded
|
|
on merge to `develop`, downloaded on PR runs). Current mechanism
|
|
requires a manual baseline-refresh PR.
|
|
- [ ] FU-4: Replace the proxy measurements in `benchmark.sh` (wall-clock curl
|
|
p99, ledger-cadence-as-TPS, ledger-cadence-as-consensus-p95) with
|
|
PromQL quantile queries from the same pipeline the regression gate uses,
|
|
and add an `rpc_methods` group to `regression-metrics.json` plus a
|
|
`defaults.rpc_method` block to `regression-thresholds.json` (without both,
|
|
any `rpc.*` metric resolves to "no threshold configured" and never gates).
|
|
- [ ] FU-6: Grafana dashboard plotting historical baseline values keyed by
|
|
commit SHA, for triaging noisy regressions.
|