Research: LMAX Sequencer Architecture (Trading Hot Path)
Objectiveβ
Define a sibling branch state on top of 009 that replaces the trading hot path's execution model
(poll + lock + blocking REST + inline JPA) with the LMAX architecture (sequenced event-sourced input,
single-threaded in-memory BLP, disruptor rings, no-GC discipline) while preserving all external
contracts and observability obligations.
Inputs Reviewedβ
LMAX-SEQUENCER-ARCHITECTURE.md,LMAX-INPUT-DISRUPTOR.md,LMAX-BLP.md,LMAX-OUTPUT-DISRUPTOR.md,LMAX-NO-GC-JAVA.md(repo root design proposals)- Martin Fowler, The LMAX Architecture; https://martinfowler.com/articles/lmax.html
specs/009-order-management-matcher/(full pack: spec, deltas, contracts, system docs, ADR-013)catalog/state-catalog.json(state lineage andC2conventions)- state
007observability stack and dashboard/probe patterns
Key Decisionsβ
- Single combined state pack. The LMAX docs staged the work as three future states
(input disruptor β fused BLP β output disruptor) plus a cross-cutting no-GC profile. Those state
IDs (
010β012) are already taken by the canonical lineage, and the requested shape is oneYU01branch; the staging survives as plan milestones P0βP4 inside this pack. - Sibling branch, not canonical lineage.
YU01branches off009; the canonical010+lineage (Kubernetes/Tilt/C3/FDC3) is unaffected. The state is registered incatalog/state-catalog.json(status: draft,primaryLineageRole: optional) because the generation pipeline's post-install steps resolve state metadata from the catalog; pipeline scaffolding (generation hook, render stub, lifecycle delegates to009) keepspipeline/generate-state.sh YU01-lmax-sequencerrunnable end-to-end, producing009-parity output until the overlay patchset lands. Letter-suffixed state ids are supported by the pipeline by treatingYU01as numeric base009for lineage thresholds while using the full prefix for script-name resolution. - Requirement ID namespace
09B+NGC. The LMAX docs' illustrativeFR-014xxblock collides with014-fdc3-intent-interoperability, so this pack usesFR-09Bxx/NFR-09Bxx/SC-09Bxx. The cross-cutting no-GC profile keeps theNGC-xxnamespace proposed inLMAX-NO-GC-JAVA.mdso hot-path NFRs can reference it. - Track
architecture. This is a behavior-preserving execution-model replacement, the same genre as005(Postgres) and006(NATS). The LMAX docs labeled their staged statesfunctional, but no functional behavior changes in this state; parity with009is a hard gate. - Journal authoritative (input doc "Option B"). The combined pack includes the output disruptor and
projector, so the coherent source-of-truth choice is the journal, with Postgres/H2 as an async,
rebuildable read-model; matching the headline design decision in
LMAX-SEQUENCER-ARCHITECTURE.mdΒ§1. - Replication/failover in scope, demo-right-sized. Follower BLPs with output suppression and
promotion are specified (FR-09B30..32); the
demo/C2profile runs a single replica with the replication contract exercised in loopback/stub mode, full failover validated on theperfprofile. - Market trades enter the sequenced stream (
TRADE_NEWevents). Derived from the sequencer doc's scope ("sequencer + matching BLP + trade ingest/booking are redesigned") and component mapping (trade-processor booking/position keeping fused into the BLP): keeping market trades on the old NATS-to-trade-processor path would leave two writers of position state and break the single-writer principle.trade-processorremains deployed only as a non-hot-path consumer until fully retired by a later state; its booking role on the trading path moves into the BLP. - Library lineage. LMAX Disruptor (rings), Agrona (off-heap buffers + primitive collections), SBE (one binary format for wire, ring, and journal), Chronicle Queue for the journal in the demo profile with Aeron Archive/Cluster as the perf-profile replication/consensus realization, OpenHFT Affinity for pinning, HdrHistogram/JMH/JLBH/jHiccup for honest measurement. Versions pinned CVE-clean per the repo dependency gate.
- Profiles split the latency dial.
demo/C2defaults toBlockingWaitStrategy, no pinning, no hugepages (container-safe, CI-friendly);perfuses busy-spin + pinned isolated cores on bare metal. The allocation gate applies to both; latency budgets bind onlyperf. - Fixed-point scale Γ1,000,000 globally (
nogc.px.scale), conversions centralized at the edges, with a penny-parity fixture against009'sBigDecimalbehavior as a release gate. - Spring stays at the edges. Java 21 + Spring Boot as in
009for lifecycle/wiring/actuator; the per-event path is plain Java and never touches Spring, JPA, or Jackson.
Risks and Mitigationsβ
- Risk: behavior drift from
009(the migration must be invisible at the edge).- Mitigation: parity gates; REST/WS/NATS subject + payload parity, penny-parity fixture, smoke
journeys identical to
009(SC-09B03/04/09).
- Mitigation: parity gates; REST/WS/NATS subject + payload parity, penny-parity fixture, smoke
journeys identical to
- Risk: hidden non-determinism (wall clock,
HashMapiteration order, RNG) breaks replay.- Mitigation: determinism contract (FR-09B14) + journal replay assertion (SC-09B06) + banned-API static check (SC-09B13).
- Risk: accidental allocation creeps onto the hot path and reintroduces GC tails.
- Mitigation: Epsilon-GC allocation gate in CI on every change (SC-09B05), JFR/async-profiler
attribution, allocation-rate metric alerting at
> 0.
- Mitigation: Epsilon-GC allocation gate in CI on every change (SC-09B05), JFR/async-profiler
attribution, allocation-rate metric alerting at
- Risk: ring undersized; backpressure stalls producers under burst.
- Mitigation: sizing math in
data-model.md(worst burst Γ slowest-handler stall Γ safety factor), remaining-capacity gauge + alert.
- Mitigation: sizing math in
- Risk: slow DB/NATS stalls matching.
- Mitigation: independent output handlers on a bounded ring; projector lags and catches up; journal remains authoritative (FR-09B24, SC-09B10).
- Risk: busy-spin/pinning/hugepages unavailable in
C2containers.- Mitigation: demo profile runs without them and still passes the allocation gate (NFR-09B06, SC-09B14).
- Risk: operational complexity (sequencer, journal, replicas, snapshots, replay).
- Mitigation: adopt Chronicle/Aeron rather than hand-rolling; phase via P0βP4; single-replica demo deployment.
- Risk: programming-model shift ("no external calls from the BLP") slows contributors.
- Mitigation: codified request/response event patterns with examples in the BLP module; ADR-015.
- Risk: over-engineering for a reference app.
- Mitigation: explicit teaching intent; demo profile right-sizes deployment; perf claims confined to documented bare-metal runs.