See It Flow
System Design · Trade-offs · ~26 min read

Stock Exchange System Design — Trade-offs & Architectural Decisions

There is no single correct architecture for an electronic exchange — every major decision in Flow Exchange's design is workload-dependent, trading latency against durability, fairness against throughput, or operational simplicity against scale. This page walks through 23 concrete decisions, the genuine alternatives for each, the baseline we chose for the assumptions stated in Complete Design, and the specific signal that would make us choose differently.

Mangesh Mandlik·Updated September 2026
Decision 01

Matching Concurrency: Single Writer vs Shared Multithreaded Book

Every order book mutation — insert, match, cancel — must appear to happen atomically and in a single agreed order, or price-time priority stops being a meaningful guarantee. The question is whether to enforce that with one thread per book or with locks across many threads.

OptionFavorsCosts
Single writer per book (one thread/event loop owns all mutations)Deterministic ordering comes for free; no lock contention inside the hot path; replay of the same command stream reproduces the same book and trades exactlyCaps a single book's throughput to one core's processing rate; a very hot symbol cannot be sped up by adding threads to that same book
Shared book with fine-grained locking (e.g. per-price-level locks)In theory lets multiple cores touch the same book concurrentlyTwo threads racing to match the same resting order need a serialization point anyway, so the lock just moves the bottleneck without removing it; introduces lock-ordering bugs, priority inversion and non-deterministic replay — the match outcome can depend on scheduler timing, which breaks the invariant that replaying a command stream yields the same trades
Lock-free/optimistic concurrent structuresAvoids blocking on contended locksCorrectness under concurrent price-time matching (two incoming orders racing for the same resting liquidity) is extremely difficult to prove; still needs a logical commit point, which in practice becomes a serialization step in disguise
Single-writer vs shared multithreaded matching

The underlying reason single-writer wins for a single book is explained at the algorithm level in Architecture Deep Dive → Matching Engine Execution Model: threads are still free to handle networking, risk checks, journaling and market-data fan-out concurrently — only the book mutation itself is serialized.

Decision 02

Order Book Storage: In-Memory vs Database-Backed Matching

The live order book is read and mutated on every single incoming command. Whether that structure lives in process memory or behind a database round-trip determines whether the matching engine can meet a microsecond-to-low-millisecond latency budget at all.

OptionFavorsCosts
In-memory order book (ordered structures + hash map, per Architecture Deep Dive)Matching happens at memory-access speed, not network/disk round-trip speed; the data shape (price-sorted levels, FIFO queues) matches the access pattern exactlyState lives only in the matching process unless paired with a durable journal — see Decision 07; a crash without a journal loses the book entirely
Database-backed book (every order row read/written through a relational or KV store)Gets durability and crash-safety 'for free' from the database's own guarantees; familiar operational toolingEvery match now costs one or more round-trips on the hot path; matching logic, which needs to walk price levels and FIFO queues repeatedly within a single command, does not map onto per-row database operations without severe latency penalty; the database quickly becomes the bottleneck under sustained order flow
In-memory structures vs database-backed book

This is not an argument against databases generally — post-trade capture, reporting, and compliance stores are database-backed by design (see Architecture Deep Dive → Post-Trade Integration). It is specifically about the structure that absorbs every match on the hot path.

Decision 03

Matching Priority: Price-Time vs Pro-Rata vs Auction-Based Allocation

When multiple resting orders are eligible to fill against an incoming order, the allocation rule decides who gets filled first — and different venues legitimately choose different rules for different instrument types.

RuleFavorsCosts
Price-time prioritySimple to reason about and explain; rewards being first at a price level (as shown in Test A: S1 fills before S2 at the same $101.00 level); predictable for market makers who arrive earlyDoes not reward size — a large resting order has no advantage over a small one at the same price besides arriving first
Pro-rata allocationCommon in some derivatives markets; allocates fills proportionally to resting order size at a price level, which can reward market makers who post large sizeHarder to explain and audit ('why did I only get 23% of my order filled') than FIFO; can incentivize quote stuffing with oversized resting orders to claim a larger pro-rata share
Auction-based (uncrossing at a single clearing price)Suited to opening/closing moments where many orders arrive before a conceptual 'go' — produces a single fair clearing price and reduces the advantage of sub-millisecond speed at that momentNot continuous — introduces a wait and a distinct matching mode (see Architecture Deep Dive → Market Orders, IOC/FOK & Stops); needs its own indicative-price and uncrossing logic, which is materially different code from continuous matching
Allocation rules
Decision 04

Price-Level Representation: Balanced Tree/Ordered Map vs Array/Tick-Indexed

Price levels need to be kept sorted so the engine can always find the best bid and best ask instantly. The data structure choice trades generality against raw lookup speed.

StructureFavorsCosts
Balanced tree / ordered map (e.g. red-black tree, skip list, ordered map type)Handles any price range without pre-allocating; insert/lookup is O(log P) where P is the number of distinct occupied price levels; straightforward to reason about and implement correctlyO(log P) is slower than O(1) array indexing at the same P, and tree-node allocation can add GC/allocator pressure in managed runtimes
Array / tick-indexed structure (index = price in ticks, bounded range)O(1) best-bid/ask and level lookup when the tick range is bounded and known ahead of time; excellent cache locality for latency-sensitive enginesNeeds a bounded, pre-sized price range (a bounded number of ticks around a reference price); a runaway price move or very wide price collar can blow past the allocated range unless handled explicitly; less flexible for instruments with unusual or very wide price ranges
Price-level structure options

Both structures are explored with pseudocode and complexity detail in Architecture Deep Dive → Order Book Data Structures; this decision is about which family to pick for a given instrument's behavior, not the implementation itself.

Decision 05

Engine Partitioning: Single Engine vs Per-Symbol Partitions

Because matching is single-writer per book (Decision 01), scaling across many instruments means scaling across independent engine instances rather than scaling one engine's internal concurrency.

OptionFavorsCosts
Single engine process handling all instrumentsSimplest to operate and reason about at small scale; one process to deploy, monitor and fail overAll instruments compete for the same single-writer loop's CPU time; a burst on one hot instrument (Test-vector style sweeps, high cancel rate) steals processing time from every other instrument sharing that process
Per-symbol (or per-symbol-group) partitions, each independently single-writerIsolates one instrument's load from another; horizontal scale-out by adding partitions as instrument count grows; a crash or slowdown in one partition does not stall unrelated instrumentsMore processes/instances to deploy, route to, monitor and fail over; needs a routing layer that reliably sends every command for a given instrument to its current owner (see Decision 20 and Architecture Deep Dive → Partitioning & Hot Instruments)
Engine partitioning options
Decision 06

Command Ordering: Central Global Sequencer vs Per-Partition Sequencing

Determinism requires every accepted command for a given book to be assigned one unambiguous position in a single serial order. The question is whether that order is assigned by one global sequencer across the whole exchange or by a sequencer scoped to each partition.

OptionFavorsCosts
Single global sequencer for the entire exchangeOne authoritative sequence number space is conceptually simple to audit end-to-endBecomes a single serialization point and potential bottleneck across every instrument, even though price-time priority is only promised per book (Section 2); concentrates failure-domain risk — a single global sequencer outage affects every instrument, not just one
Per-partition (per-instrument-group) sequencerMatches the actual correctness requirement exactly — ordering only needs to be deterministic within a book, not across books (Section 2's explicit non-promise of a universal total order); each partition's sequencing can scale and fail independentlyNo single number tells you 'the Nth event across the whole exchange'; cross-instrument causality claims require correlating timestamps/sequence numbers across partitions deliberately, not assuming a shared counter
Sequencing scope options
Sequencer Resolves the Cancel/Fill RaceCancel(S1)arrivesBUY 60arrivesSequencerassigns ONE orderWhichever one is sequenced first is simply what happened — never decided by raw network arrival time.
Per-partition sequencing: each instrument's commands get one deterministic order; different instruments are not comparable on a shared counter
Decision 07

Persistence: Synchronous WAL vs Group Commit vs Asynchronous Journal

Every accepted command must be durable before it is acknowledged as committed — but exactly when 'durable' happens relative to 'acknowledged' is a direct trade between the durability guarantee and acknowledgment latency.

StrategyFavorsCosts
Synchronous write-ahead log, fsync before ackStrongest possible durability guarantee — nothing is acknowledged that is not already safely on durable storageEvery single command pays the full disk-flush latency individually; under high command rates this serializes the hot path on storage I/O
Group commit (batch several pending commands, fsync once, ack the whole batch)Amortizes flush cost across many commands, recovering most of the throughput lost to per-command fsync while still giving every acknowledged command a durable positionAdds a small, bounded wait for the batch window, which slightly increases the latency of the earliest command in a batch; batch-size/time tuning is itself a trade-off
Fully asynchronous journal (ack before durable write lands)Lowest possible acknowledgment latencyA crash between acknowledgment and durable write produces a committed-looking order the journal never actually recorded — violates the durable-and-replayable invariant (Section 4) and risks silent data loss that a client cannot distinguish from a dropped acknowledgment
Commit strategies

The exact commit-point definition and a concrete crash-between-commit-and-ack walkthrough are covered in Architecture Deep Dive → Journal, Commit & Replay and Failure & Scale Scenarios' crash incidents.

Decision 08

Replication: Active-Passive vs Active-Active for the Same Book

A book needs a standby in case its current owner fails — but letting two nodes both believe they own the same book at the same time is a correctness violation, not a performance optimization.

TopologyFavorsCosts
Active-passive with leader fencing (single writer, epoch-fenced standby)Exactly one authoritative matching process per book per epoch, by construction; standby catches up from the journal and takes over cleanly on failover, as shown in Architecture Deep Dive → Replication & Leader FencingA failover has a brief unavailability window while the standby catches up and is promoted; throughput ceiling is still the single active node's capacity
Active-active (both nodes able to accept and match independently against the same book)In principle, more aggregate throughput and no failover gapTwo nodes matching the same book independently can produce two different, conflicting trade histories for the same resting liquidity — this directly violates the single-active-leader invariant (Section 4) and the no-dual-primaries rule (Section 2); reconciling or discarding one side's trades after the fact is not an acceptable correctness model for executed trades
Replication topology for one book
Epoch Fencing — No Two Active PrimariesPrimary (epoch 1)crashedStandby (epoch 1)replaying journalfenced ✗Promoted Primary (epoch 2)resumes from last journal seqThe old primary can never write again, even if it reconnects — a new epoch number is the only valid writer.
Active-passive with epoch fencing: a fenced former leader cannot resume matching even if it reconnects
Decision 09

Recovery: Journal-Only Replay vs Snapshot + Incremental Replay

After a crash or planned restart, the engine must rebuild an exact in-memory book from durable state. How far back it has to replay from determines recovery time.

StrategyFavorsCosts
Journal-only replay (replay every event from the beginning of time)Simplest possible recovery model — one source of truth, no separate snapshot artifact to manage or validateRecovery time grows unbounded with total journal length; a long-lived, high-volume instrument eventually takes an unacceptably long time to recover, directly hurting recovery-time objectives
Periodic snapshot + replay of the incremental tail (snapshot at sequence N, replay N+1 onward)Bounds recovery time to roughly 'snapshot load time + events since last snapshot', independent of total history length; snapshot interval is a tunable dialNeeds snapshot generation to not stall or corrupt the live book, snapshot checksums/versioning (Architecture Deep Dive → Journal, Commit & Replay), and a policy for a corrupt or missing snapshot falling back to an older one plus more replay
Recovery strategies
Decision 10

Protocol: FIX vs Custom Binary Order Entry

Order entry needs a wire format that both sides agree on, that handles retransmission and gaps, and that is fast enough for the latency budget. FIX and custom binary protocols sit at different points on that trade-off.

ProtocolFavorsCosts
FIX (or FIX-derived tag-value/session semantics)Widely understood session/sequence/resend concepts; broker-side integration teams are frequently already familiar with the message model; easier onboarding for new membersTag-value text encoding carries more parsing and bandwidth overhead than a tightly packed binary format, which matters more as message rates climb
Custom binary order-entry protocolMinimal parsing and framing overhead, favorable for the tightest latency budgetsRequires every participant to implement and test a proprietary format; no existing tooling/libraries to lean on; versioning and schema evolution must be built and governed in-house, as must session/resend semantics that FIX already standardizes
Protocol options

Message framing, versioning, checksums, heartbeats and session reset mechanics for both families are covered in Architecture Deep Dive → Network Protocols & Session Management; this is not every venue standardizing on the same stack — real exchanges genuinely differ here.

Decision 11

Data Transport: TCP vs UDP Multicast

TCP and UDP multicast solve different problems and are not universal substitutes for each other — the right choice depends on whether the data is a reliable one-to-one session or a lossy-tolerant one-to-many broadcast.

Use caseTransportWhy
Order entry (new/cancel/replace, execution reports)TCPNeeds reliable, ordered, one-to-one delivery with retransmission and backpressure built into the transport; losing or reordering an order command silently is unacceptable
Market-data distribution (book deltas, trade prints) to many subscribersUDP multicast where the network supports itOne publisher, many simultaneous subscribers; multicast avoids the publisher having to send N individual copies over N TCP connections; the protocol is explicitly designed to tolerate loss because sequence numbers plus snapshot/gap-recovery (Decision 12, Architecture Deep Dive → Market Data Architecture) handle it at the application layer instead
Transport by use case
Decision 12

Market Data: Push Deltas vs Polling vs Snapshot-Only

Subscribers need to see the book and trade prints change in near real time without putting read load anywhere near the matching hot path.

ModelFavorsCosts
Push deltas (snapshot + incremental sequence-numbered updates)Lowest latency from book change to subscriber visibility; bandwidth scales with actual change rate, not subscriber polling rate; gap detection via sequence numbers enables precise resyncSubscribers must implement gap detection and snapshot-resync logic correctly, or they silently drift from the true book
Polling (subscriber periodically requests current state)Simple subscriber implementation; no persistent connection or sequence-tracking logic neededEither wastes requests when nothing changed or misses intermediate book states between polls; poll frequency vs load is a constant tuning fight, and poll traffic itself can become a load problem at scale
Snapshot-only (no incremental deltas, full snapshot on every update or interval)Simplest possible protocol — no sequence numbers, no gap logicBandwidth cost scales with full book size times update frequency instead of change size, which is wasteful for a deep, active book; higher latency per update for large books
Market-data delivery models
Decision 13

Hot-Path Messaging: Direct Engine Pipeline vs General-Purpose Message Broker

Within the matching hot path — gateway to risk to sequencer to engine to journal — every extra hop costs latency and, more importantly, every extra layer of indirection risks reordering the very commands whose order must be deterministic. This is the one decision where the industry default ('just put a message broker in the middle') deserves explicit scrutiny rather than being adopted unquestioned.

OptionFavorsCosts
Direct engine pipeline (purpose-built in-process/inter-process queue dedicated to one partition's command flow, tuned specifically for ordering and latency)No general-purpose broker overhead (topic/partition metadata lookups, consumer group coordination, serialization layers designed for broad reuse rather than this one hot path); ordering guarantee is a direct property of the pipeline's own design rather than something layered on top of a general toolPurpose-built code to build and maintain; fewer off-the-shelf operational tools than a mainstream broker
General-purpose message broker (e.g. a Kafka-style log) placed directly in the matching hot pathMature tooling, monitoring and client libraries; team may already operate it for other asynchronous workloadsA general broker is built for durable multi-consumer fan-out and replay, not minimal-latency single-partition ordering — the throughput/latency profile and reordering-under-retry semantics of a general broker were not designed around the sequencing-fairness guarantee the matching engine needs; depending on configuration, consumer rebalances, partition reassignment or at-least-once redelivery semantics can reorder or duplicate messages relative to the exact order a sequencer must preserve, which is precisely the invariant this engine cannot compromise on
Hot-path transport options

This directly reflects Section 2's explicit constraint: no 'Kafka in the matching hot path' as an unquestioned default. The question to ask before adopting a general broker on this specific path is whether its ordering and latency model was built for exactly this job, not whether it is popular or already running elsewhere in the stack.

Decision 14

Risk Validation: Synchronous Pre-Trade Checks vs Deferred Checks

Pre-trade risk checks (order size, notional, price collar, symbol permission) add latency on the path before a command is even sequenced. The question is whether that check must block sequencing or can be relaxed.

ApproachFavorsCosts
Synchronous pre-trade checks (block before sequencing/matching)Guarantees an order that fails a hard risk rule (bad tick, excessive size, halted symbol) never reaches the book at all — the strongest possible protection against a rule violation ever becoming a committed orderAdds the risk-check latency to every single command's path to acceptance; risk-state freshness (credit, position limits) must be kept current enough to check against without itself becoming a bottleneck
Deferred checks (accept into the pipeline, validate after sequencing, reject/unwind if a check fails)Removes risk-check latency from the critical-acceptance pathAn order can briefly exist inside the sequenced/matching pipeline before a check catches it, which risks allowing a rule violation to actually match before it's caught — unwinding a matched trade after the fact is not a clean operation (Section 2: a completed cancel cannot undo an earlier committed fill, and the same logic applies to unwinding executions)
Risk check timing
Decision 15

Cancel/Replace: In-Place Mutation vs Cancel/New With Priority Consequences

Amending a resting order's price or size can either preserve its existing place in the FIFO queue or push it to the back, as if it were a fresh order — and that choice changes the fairness guarantee for every other resting order at that price.

ApproachFavorsCosts
In-place mutation preserving time priority (allowed for qualifying amendments, typically a size decrease only)A participant lowering their remaining size does not need to lose their place in line — reasonable, since reducing size can't disadvantage orders behind it in the queueRequires a precisely defined rule for exactly which amendment types qualify (e.g. decrease-only); any price change or size increase cannot safely preserve priority without disadvantaging orders already resting behind it
Cancel/new semantics (replace cancels the old order and inserts a new one at the back of its new price level's queue)Simple, uniform rule: any amendment that could affect other orders' relative position forfeits the original queue position, which is fair to orders that were already restingA participant who wants to adjust price slightly loses queue priority entirely, which can be a meaningful cost for a market maker constantly refreshing quotes near the touch
Replace semantics

The precise state machine, versioning and idempotency handling for replace are covered in Architecture Deep Dive → Cancel/Replace Semantics; this decision is about the priority policy, not the mechanics of applying it.

Decision 16

Order Types: Simple First vs Advanced/Hidden/Stop/Auction Rules

Market and limit orders with Day/IOC/FOK time-in-force cover the large majority of educational and practical matching scenarios. Iceberg, stop, and auction order types each add meaningfully different logic, not just extra fields.

TierIncludesWhy it's a separate tier
Core (build and prove correct first)Limit, market; Day, IOC, FOK time-in-forceThese exercise continuous price-time matching, partial fills, and all-or-nothing feasibility directly, and every test vector in Section 4 is built on exactly this tier
Advanced, additiveIceberg/hidden orders, stop and stop-limit orders, opening/closing/volatility auctionsIceberg changes what 'visible depth' even means and interacts with priority (Architecture Deep Dive explains the priority implications); stops require a separate trigger-and-release model, not resting-book matching, until triggered; auctions are a distinct matching mode (uncrossing at a clearing price), not a variant of continuous matching
Scope sequencing for order types
Decision 17

Fairness vs Latency: Admission and Sequencing Policy Tuning

Once commands reach the sequencer, the policy for how it admits and orders them can be tuned for raw speed or for treating similarly-timed arrivals fairly — and pushing too far toward either extreme has a real cost.

Policy leanFavorsCosts
Latency-optimized (process and sequence as fast as physically possible, minimal batching/smoothing)Lowest possible time from gateway receipt to sequenced position, which matters directly to latency-sensitive participantsCan make outcomes sensitive to tiny, effectively-arbitrary timing differences between near-simultaneous arrivals — two orders a few microseconds apart may be ordered in ways no participant can meaningfully anticipate or verify, which strains the credibility of the fairness story even though the ordering itself is still deterministic once fixed
Fairness-oriented (bounded intake window or published, defensible tie-break rule for very close arrivals)Easier to explain and defend as fair across all participants regardless of connection speed; reduces the incentive to spend disproportionate effort purely on shaving microseconds off network pathAdds a small, deliberate delay or batching window to the admission path, which raises the latency floor for everyone, including participants who did nothing to deserve the wait
Sequencing/admission policy spectrum

Whatever policy is chosen, the sequencer remains the sole ordering authority — see Decision 21 and Architecture Deep Dive → Command Sequencing & Fairness for how retries, reordering and gateway failover are handled without ever falling back to wall-clock comparisons.

Decision 18

Availability vs Safety: Fail-Closed/Halt vs Accepting Uncertain Orders

When a dependency the engine needs for correctness becomes unavailable or uncertain — risk state is stale, the journal can't confirm a write, a partition's ownership is ambiguous — the system must choose between stopping and continuing on uncertain information.

PostureFavorsCosts
Fail closed / halt the affected instrument or pathNever matches an order under conditions that cannot be verified as correct; keeps the invariant that a book never diverges from its true, auditable stateTrading visibly stops for affected participants, which has a real cost (missed opportunity, participant frustration) and must be communicated clearly
Continue accepting/matching under uncertainty (e.g. proceed with possibly-stale risk data, or accept orders during a durability-uncertain window)Keeps the venue 'available' in a narrow uptime senseRisks an unrecoverable correctness violation — e.g. a trade executed against a limit that should have been rejected, or a durability gap that produces an order the journal never actually has a record of; such violations cannot be cleanly reversed once a trade has executed (Section 2)
Availability vs safety posture
Decision 19

Scale Strategy: Faster Single-Book Engine vs More Symbol Partitions

When overall exchange throughput needs to grow, there are two distinct levers: make each single-writer engine process commands faster, or add more independently-owned partitions. They solve different bottlenecks.

LeverSolvesDoes not solve
Faster single-book engine (better data structures, memory layout, reduced allocation, CPU/NUMA tuning — see Architecture Deep Dive → Latency Engineering)A single hot instrument that is CPU-bound on its own processing, independent of how many other instruments existTotal exchange-wide throughput across thousands of instruments — one faster core still has a ceiling, and most instruments are not individually CPU-bound in the first place
More symbol partitions (horizontal scale-out across independent books)Aggregate exchange-wide throughput as instrument count and overall order volume growA single pathologically hot instrument's own per-core ceiling — adding partitions for other symbols does nothing for one symbol that is itself CPU-bound
Scale levers
Decision 20

Geographic Topology: One Authoritative Matching Region vs Distributed Gateways

Matching for a given book must have exactly one authoritative location at any moment, but the gateways that accept orders from participants can be geographically distributed to reduce access latency.

OptionFavorsCosts
Single authoritative matching region, local gateways onlySimplest to reason about; no cross-region replication complexity for the book itselfParticipants far from the matching region see higher round-trip latency with no local mitigation
One authoritative matching region plus geographically distributed gateways that forward into itReduces local network hop latency for the last mile to the nearest gateway, without multiplying matching authoritiesGateway fleet and session management become geographically distributed, needing careful failover and consistent routing to the single authoritative region; the cross-region hop from gateway to matching region is still there for the actual order-to-ack round trip
Fully distributed/multi-region active matching for the same bookWould, in principle, reduce latency for every region symmetricallyReintroduces the same correctness problem as active-active replication (Decision 08) at a geographic scale — two regions both matching the same book is two primaries, which this design explicitly prohibits; this is a different instrument-ownership topology, not a loophole around single-leader matching
Geographic topology options
Decision 21

Timestamp Authority: Sequencer Order vs Wall-Clock Ordering

It is tempting to order commands by the wall-clock time they were received, but clocks across different gateway machines are never perfectly synchronized, and network jitter means receipt time does not reliably reflect true arrival order anyway.

ApproachFavorsCosts
Sequencer-assigned monotonic sequence number as the sole ordering authorityDeterministic and reproducible regardless of clock skew between machines; replay of the same sequence always yields the same matching outcome — a direct requirement from Section 2 and Section 4The sequence number does not, by itself, tell you the real-world wall-clock moment an order arrived — wall-clock timestamps are still recorded alongside it, just not used for ordering decisions
Wall-clock timestamp comparison across gateways/machinesIntuitive — 'whichever arrived first by the clock' feels fairClock drift and network jitter between machines make wall-clock ordering non-deterministic and non-reproducible; two runs of the same physical event sequence could order commands differently depending on momentary clock skew, which breaks deterministic replay outright — this is explicitly called out in Section 2 as a required distinction
Ordering authority options

Wall-clock timestamps remain essential for audit records, latency measurement and compliance traceability (Architecture Deep Dive → Command Sequencing & Fairness and Security, Audit & Observability) — they are simply never the mechanism that decides match order.

Decision 22

Trade Publication: Synchronous Outbound Reporting vs Committed Event-Driven Fan-Out

Once a match commits, execution reports must reach both counterparties and trade prints must reach the market-data pipeline and post-trade integration. Whether that happens synchronously inline with the match or via a committed event handed off for independent fan-out changes both latency and failure isolation.

ModelFavorsCosts
Synchronous outbound reporting (engine blocks on delivering reports/events before considering the command fully done)Conceptually simple — one linear sequence from match to deliveryA slow or unavailable downstream consumer (a sluggish execution-report gateway, a backed-up market-data publisher) stalls the matching engine itself, which is exactly the kind of non-critical-path leak Section 2 and this module's architecture repeatedly warn against
Committed event-driven fan-out (engine durably commits the trade/execution event; delivery to reports, market data and post-trade is a decoupled, independently-retriable consumer process)Matching never blocks on a downstream consumer's health; each consumer (execution-report gateway, market-data publisher, post-trade capture) can retry, catch up or recover independently without affecting the others or the engineRequires the commit itself to be the durability point — the event must be committed before any consumer sees it — and consumers must handle at-least-once delivery with idempotent processing keyed on unique trade/execution IDs
Trade publication models
Decision 23

Operational Complexity: Custom Low-Latency Stack vs Conventional Managed Infrastructure

Every latency-engineering technique discussed in Architecture Deep Dive — kernel bypass, CPU pinning, NUMA-aware allocation, busy-polling — trades operational simplicity for tail-latency improvement. Most of the exchange does not need to pay that cost.

Component classFavorsCosts
Custom low-latency stack (tuned kernel/network settings, CPU affinity, specialized allocators, bespoke pipeline code)Meaningfully reduces p99/p99.9 latency and jitter for the specific hot-path components that need it — sequencer, matching engine, journal commitSpecialized operational knowledge to run and debug; harder to hire for and onboard new engineers into; conventional cloud/container tooling (autoscaling, generic monitoring dashboards) often does not apply cleanly to pinned, tuned processes
Conventional managed infrastructure (standard container orchestration, managed databases/queues, off-the-shelf monitoring)Familiar operational tooling, faster onboarding, strong ecosystem support, easier to staffNot tuned for the tightest latency requirements of the matching hot path specifically — scheduling jitter, network virtualization overhead and generic resource isolation all work against sub-millisecond consistency
Stack choice by component
Summary

Decision Record: All 23 Trade-offs at a Glance

No row in this table is a universal truth — each baseline choice is correct for the assumptions stated across this module (correctness and deterministic replay prioritized over raw single-book throughput; per-instrument isolation preferred over a single shared engine; fail-closed over uncertain availability). Change the assumptions, and some of these choices change with them.

#DecisionBaseline choiceRationaleReconsider when
01Matching concurrencySingle writer per bookDeterministic ordering and replay without lock contentionA single instrument is sustained-CPU-bound, not merely bursty
02Order book storageIn-memory, journal-backedMatching needs memory-speed access; durability comes from the journal, not sync DB writesA product requirement removes the need for low-latency continuous matching entirely
03Matching priorityPrice-time priority (continuous)Simple, auditable, and what every canonical example demonstratesA market-structure goal explicitly rewards size (pro-rata) or requires a scheduled clearing moment (auction)
04Price-level representationBalanced tree/ordered map per instrumentNo per-instrument tuning needed; handles any price range safelyA specific hot instrument has a small, stable, provably-bounded tick range
05Engine partitioningPer-symbol partitionsIsolation is a fairness/correctness property, not just performanceOperational overhead of many small partitions outweighs isolation for genuinely cold symbols (group them)
06Command orderingPer-partition sequencerMatches the actual per-book ordering requirement; avoids a global bottleneckA new requirement demands cross-instrument causal ordering (rare, out of current scope)
07PersistenceGroup commitKeeps the durable-before-ack contract while amortizing fsync costMeasured throughput at very low command rates makes per-command sync acceptable, or batch latency exceeds budget
08ReplicationActive-passive with leader fencingExactly one active matcher per book per epoch — a correctness requirement, not a preferenceNever — active-active on one book is unsafe by definition
09RecoverySnapshot + incremental replayBounds recovery time independent of total history lengthMeasured recovery time in a drill exceeds the stated recovery-time objective (tune snapshot interval)
10ProtocolFIX-style order entryBroad member onboarding and familiarity prioritized over micro-latency encoding gainsA specific member's measured latency requirement cannot be met by tag-value parsing overhead
11Data transportTCP for order entry, UDP multicast for market dataEach transport matches the reliability/fan-out shape of its trafficNetwork path cannot support multicast reliably (fall back to TCP feed for those subscribers)
12Market dataSnapshot + incremental push deltasMatches the required snapshot-plus-contiguous-deltas reconstruction guaranteeA consumer class cannot implement gap detection correctly (fix at the client-library layer)
13Hot-path messagingDirect, purpose-built pipelineGeneral-broker ordering/latency semantics were not built for single-writer sequencingOff the hot path (post-match fan-out) — see Decision 22 — where a general broker is the right fit
14Risk validationSynchronous pre-trade checksA hard rule violation must never become a committed order; executions can't be cleanly unwoundOnly for checks whose failure mode is safe to detect and reconcile after the fact (non-blocking audits)
15Cancel/replaceCancel/new, with time-priority kept only for same-price size decreasesOne simple, auditable fairness rule instead of a continuum of partial-priority exceptionsA clearly-scoped, explicitly published market-making incentive program needs a different stated rule
16Order typesCore types first (limit/market, Day/IOC/FOK), advanced types layered inCore tier is what every required test vector validates; advanced types need their own correctness reviewNever as a silent default — advanced types ship only with their own explicit design and tests
17Fairness vs latencyLatency-optimized sequencer, published deterministic tie-breakThe sequencer's deterministic order is itself the fairness guaranteeA demonstrated, measurable network-path advantage repeatedly determines outcomes
18Availability vs safetyFail closed on correctness-critical dependenciesAn unrecoverable correctness violation is worse than a visible, communicated haltOnly for genuinely non-critical, reversible paths (e.g. a delayed, non-authoritative feed tier)
19Scale strategyHorizontal partitioning as primary lever; single-engine speed for identified hot symbolsThe two levers solve different bottlenecks and are complementaryPer-partition CPU/queue metrics show which lever the current bottleneck actually needs
20Geographic topologyOne authoritative matching region, distributed gatewaysMatching authority must stay singular; gateways can still reduce access latencyNever for matching authority itself — a genuine multi-venue product is a different system, out of scope
21Timestamp authoritySequencer sequence numberDeterministic replay requires it; wall-clock is recorded but never decides orderNot reconsiderable within this design's determinism requirement
22Trade publicationCommitted event, then decoupled fan-outMatching must never block on a downstream consumer's healthDelivery lag to consumers exceeds the stated reporting SLA (scale consumers, don't move delivery onto the hot path)
23Operational complexityCustom low-latency stack only for sequencer/engine/journal; conventional infra elsewhereLatency engineering cost should track where the latency guarantee actually mattersMeasurement shows a specific component is genuinely on the critical path for the stated budget
Decision record — baseline, rationale, reconsideration trigger
Key takeaways
  • Almost every decision here is reversible given a changed assumption — the two that are not (active-active replication on one book, and wall-clock as the matching order authority) are excluded by correctness invariants, not by current workload.
  • The recurring pattern is: keep the matching hot path narrow, deterministic and single-writer per book, and push everything that can tolerate asynchrony (reporting, market-data fan-out, post-trade, analytics) off that path into decoupled, independently-scalable consumers.
  • A 'Kafka in the hot path' default is specifically rejected for sequencer-to-engine-to-journal (Decision 13), while a general-purpose broker is specifically recommended for post-commit fan-out (Decision 22) — the same technology, two different fits, decided by where the ordering guarantee has to live.
  • For incident-driven reconsideration of these baselines, see Failure & Scale Scenarios; for the algorithms and pseudocode behind each decision, see Architecture Deep Dive; for interview framing of how to present these trade-offs under time pressure, see Interview Perspective.