Limit order book matching engine in Rust

lobster

Built to explore low-latency design: cache-friendly structures, an allocation-free hot path, and honest measurement. Every number here is a replay you can rerun.

96.5 M ops/s
Replay throughput, v5, Apple M5
440 ns
Median latency through two pinned threads at 1 M/s, EC2 c5.xlarge

01 / Evolution

Six versions, each step backed by a profile.

Replay throughput on an Apple M5, 1,000,000 commands, seed 42. Hover a row for the change.

  • v1
    21.8M/s
    ~46 ns/op
  • v1.1
    28.0M/s
    ~36 ns/op
  • v2
    32.5M/s
    ~31 ns/op
  • v3
    48.0M/s
    ~21 ns/op
  • v4
    98.7M/s
    ~10 ns/op
  • v5
    96.5M/s
    ~10 ns/op

v5 reads slightly below v4 on the narrow workload (98.7 to 96.5). The bitmap earns its keep on sparse books, shown next.

02 / Stress workloads

Same engine, four very different books.

The default workload is the best case for an array-indexed ladder. These four push on footprint, scan length, and stream shape. Throughput in M ops/s on the M5.

v4 v5

narrow

~5-9k resting orders, ~1.2k tick range

The bitmap costs a bit set or clear whenever a level fills or empties, on a workload that never had a scan problem: about -4%.

03 / Pipeline latency

Two threads, one ring, 440 ns in the middle.

A paced sender pushes commands through a lock-free ring to the engine thread. Latency runs from the moment a command was due to the moment its events were published, so queueing is counted, not hidden.

p50
440 ns
p90
625 ns
p99
3.6 µs
p99.9
14 µs
max
76 µs

Log scale, 100 ns to 100 µs.

Capacity is about 6.3 M/s with every command published on its own (batch 1). Above that, the rows marked * saturate.

Pinning changed nothing measurable. The tails are nearly the same pinned and unpinned, so thread migration is not the cause. Their cause has not been isolated.

AWS EC2 c5.xlarge, ap-south-1, Ubuntu 24.04, kernel 7.0.0-1014-aws, Xeon Platinum 8275CL @ 3.0 GHz, 4 vCPU (2 cores x 2 threads). narrow, 1M commands, median of 5 runs.

04 / Method

Where the numbers came from.

Two machines, never mixed in one table. The limits are listed because they change how far a number should be trusted.

Apple M5 MacBook Air

macOS, 16 GB, plugged in

Used for

Engine versions and stress workloads

No hard core pinning on Apple Silicon. The timer tick is about 42 ns.

AWS EC2 c5.xlarge

ap-south-1, Ubuntu 24.04, kernel 7.0.0-1014-aws, Xeon Platinum 8275CL @ 3.0 GHz, 4 vCPU (2 cores x 2 threads)

Used for

Pipeline latency

Non-burstable VM, no isolated cores. Threads pinned to CPUs 0 and 1, which sit on different physical cores.