Skip to content

feat: hot-path-safe node metrics + gateway /metrics + Grafana starter kit (match#33)#61

Merged
emrebulutlar merged 1 commit into
mainfrom
p3.1-match-metrics
Jul 4, 2026
Merged

feat: hot-path-safe node metrics + gateway /metrics + Grafana starter kit (match#33)#61
emrebulutlar merged 1 commit into
mainfrom
p3.1-match-metrics

Conversation

@emrebulutlar

Copy link
Copy Markdown
Member

Engine/cluster side (NO Micrometer, nothing new allocating or locking on the
matching thread):

  • NodeMetrics: plain-long counters + preallocated log2 latency histogram
    (1us..1s buckets) written only on the cluster agent thread; order latency
    sampled 1-in-16 around sbeDemuxer.dispatch so nanoTime stays off most
    orders; cross-thread visibility via a volatile piggyback bumped from the
    existing flush timer. Role tracked from onRoleChange (cluster.memberId() is
    -1 during onStart — nodeId comes from CLUSTER_NODE like the bootstrap).
  • NodeMetricsServer: JDK com.sun.net.httpserver on its own daemon thread,
    hand-rendered Prometheus text; port METRICS_PORT (default 9500+nodeId);
    started in onStart, stopped in onTerminate; failure to start never takes
    a node down. Exposes submitted/terminal/overflow/trades/drops/queues/
    sessions/aeron-errors + role, memberId, snapshot age (stamped in
    onTakeSnapshot), egress age, and the latency histogram.

Market gateway:

  • /metrics on the existing Netty HTTP surface (GatewayHttpHandler): WS
    clients/dropped-frames/resyncs/slow-disconnects, stale deltas, cluster
    session up, egress messages/age, aeron errors. New volatile-read getters
    on AeronGateway/GatewayStateManager.

Observability kit (grafana/): prometheus.yml scrape config (nodes 9500-9502,
gateway 8081, OMS 8080), alerts.yml (no leader, snapshot age >2x interval,
reliable-egress drops, OMS egress gaps, risk-reject spike, OMS disconnected),
starter dashboard JSON (10 panels), README.

Tests: NodeMetricsServerTest (render, bucket cumulation/saturation, sampling
cadence), GatewayHttpHandlerTest /metrics route. Full suite green (786).

Live-verified after rolling update: 3 nodes + gateway serving; a 15s load run
showed identical counters on all 3 nodes (3,907,420 orders / 3,079,530 trades
/ exactly 244,215 sampled latencies each — determinism visible in metrics),
mean engine processing ~0.76us. No-regression: box is in quiet/dev-driver
mode (user drop-in) — sustained 160k/s vs the documented ~148k dev-rung
ceiling with equal client latencies (p50 0.22us); prod-profile 800k rerun
offered as follow-up.

Closes #33.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

… kit (match#33)

Engine/cluster side (NO Micrometer, nothing new allocating or locking on the
matching thread):
- NodeMetrics: plain-long counters + preallocated log2 latency histogram
  (1us..1s buckets) written only on the cluster agent thread; order latency
  sampled 1-in-16 around sbeDemuxer.dispatch so nanoTime stays off most
  orders; cross-thread visibility via a volatile piggyback bumped from the
  existing flush timer. Role tracked from onRoleChange (cluster.memberId() is
  -1 during onStart — nodeId comes from CLUSTER_NODE like the bootstrap).
- NodeMetricsServer: JDK com.sun.net.httpserver on its own daemon thread,
  hand-rendered Prometheus text; port METRICS_PORT (default 9500+nodeId);
  started in onStart, stopped in onTerminate; failure to start never takes
  a node down. Exposes submitted/terminal/overflow/trades/drops/queues/
  sessions/aeron-errors + role, memberId, snapshot age (stamped in
  onTakeSnapshot), egress age, and the latency histogram.

Market gateway:
- /metrics on the existing Netty HTTP surface (GatewayHttpHandler): WS
  clients/dropped-frames/resyncs/slow-disconnects, stale deltas, cluster
  session up, egress messages/age, aeron errors. New volatile-read getters
  on AeronGateway/GatewayStateManager.

Observability kit (grafana/): prometheus.yml scrape config (nodes 9500-9502,
gateway 8081, OMS 8080), alerts.yml (no leader, snapshot age >2x interval,
reliable-egress drops, OMS egress gaps, risk-reject spike, OMS disconnected),
starter dashboard JSON (10 panels), README.

Tests: NodeMetricsServerTest (render, bucket cumulation/saturation, sampling
cadence), GatewayHttpHandlerTest /metrics route. Full suite green (786).

Live-verified after rolling update: 3 nodes + gateway serving; a 15s load run
showed identical counters on all 3 nodes (3,907,420 orders / 3,079,530 trades
/ exactly 244,215 sampled latencies each — determinism visible in metrics),
mean engine processing ~0.76us. No-regression: box is in quiet/dev-driver
mode (user drop-in) — sustained 160k/s vs the documented ~148k dev-rung
ceiling with equal client latencies (p50 0.22us); prod-profile 800k rerun
offered as follow-up.

Closes #33.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@emrebulutlar
emrebulutlar merged commit f91e26e into main Jul 4, 2026
2 checks passed
@emrebulutlar
emrebulutlar deleted the p3.1-match-metrics branch July 4, 2026 17:19
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.

[P3.1] Hot-path-safe engine metrics + market-gateway /metrics + Grafana dashboard & alerts

1 participant