Design a Matching Engine
A stock exchange makes four promises at once — fairness, determinism, microsecond latency, and never losing an order — and one data structure keeps all four. Built from zero: what an exchange must guarantee, the order book as sorted price levels each holding a doubly-linked FIFO plus an id-map (place, match, and cancel all O(1), and the singly-linked trap that ruins it), a live book where you fire a market buy and watch it sweep the ask side with honest fills, the sequencer that stamps every order so the same input always replays the same fills, the single-box mmap event bus that beats the network by three orders of magnitude, hot-warm failover, and the p99 tail that a garbage-collection pause quietly ruins.
System design · Systems. The source ↗
A free, interactive, animated visual explainer of Design a Matching Engine — built to be understood, not skimmed.
Questions
- What is a matching engine?
- A matching engine is the core of an exchange: the single component that holds every resting buy and sell order for an instrument and pairs them off the instant two orders can trade. It keeps a limit order book — all the unfilled orders, sorted by price — and enforces the rules of who trades with whom and in what order. When a new order arrives, the engine either matches it against the best-priced orders on the other side (producing trades, called fills) or rests it in the book to wait. Everything an exchange promises — a fair price, a trade that actually happens, an audit trail regulators can trust — is enforced here, which is why the matching engine is built to four demands simultaneously: fairness, determinism, microsecond latency, and never dropping an acknowledged order.
- How does an order book match orders? What is price-time priority?
- The book is sorted by price first, then by time. Price-time priority means a matching engine always fills the best price available, and among orders sitting at the same price it fills the one that arrived earliest — first in, first out. So a market buy walks the sell side starting at the lowest ask, taking the whole queue at that price in arrival order before moving up to the next price level. This is exactly why the data structure works: each price level is a first-in-first-out queue, new orders are appended to the tail, and a match always removes from the head. WK Selph, in the canonical write-up on building a fast book, frames the whole design around implementing add, cancel, and execute "in O(1) time" — constant time regardless of how deep the book gets — because at market speed the engine cannot afford to scan.
- Why is a matching engine deterministic, and why does that matter?
- Deterministic means the same sequence of inputs always produces exactly the same sequence of outputs — feed the engine the identical stream of orders and you get byte-identical fills, every time, on any machine. Exchanges get this by stamping every inbound order with a sequence number the moment it arrives, then processing strictly in that order, with no wall-clock reads, no random tie-breaks, and no dependence on thread timing. Determinism buys two things that are otherwise impossible. First, recovery: because, as Martin Fowler writes of the LMAX exchange, "you can always recreate the current state of the business logic engine by replaying the events," a crashed engine rebuilds its exact book by replaying the stamped stream. Second, a hot spare that replays the same stream stays bit-for-bit identical to the primary, so failover loses nothing. A single non-deterministic bug — an unordered map iterated in hash order, say — silently breaks both.
- Why do exchanges run the matching engine on a single machine, in memory?
- Because the latency budget forbids anything else. A network round-trip to another service or a database is hundreds of microseconds; a match against an in-memory book is well under one. If the critical path crosses the network even once per order, the exchange is thousands of times too slow. So the whole engine lives on one box, in RAM, on one core: Fowler describes the LMAX design as running "all trades, from all customers, in all markets — on a single thread. A thread that will process 6 million orders per second using commodity hardware," and notes it "operates entirely in-memory, there is no database or other persistent store." Durability comes not from a database but from event sourcing — journaling the stamped input stream — and scale comes from making one core absurdly fast rather than spreading work across many.
- What happens to a matching engine when it crashes?
- Nothing is lost, because the engine never trusted its own memory as the source of truth — the stamped input stream is. Two mechanisms cover a crash. A hot-warm pair keeps a second engine replaying the identical sequenced stream in lockstep; when the primary stops sending heartbeats, the warm engine — already holding a bit-identical book — promotes itself in microseconds. And for a cold restart, the engine replays its journal from the last snapshot to rebuild the exact book: at LMAX, "a full restart — including restarting the JVM, loading a recent snapshot, and replaying a days worth of journals — takes less than a minute." The only genuinely dangerous failure is a non-deterministic bug that makes the warm replica diverge from the primary, so that the spare you promote holds a different book than the one that just died.