Ride-Sharing Dispatch, Actually Explained
Finding the nearest available driver sounds like a database query. It isn't — not at real scale. A ride-sharing platform is a two-sided marketplace where both sides are moving and arriving continuously, and a match that's locally correct for one rider can still be a worse outcome for the city. Run the three simulators below and watch a greedy match lose to a batch, a race condition double-book a driver, and a naive price loop spiral before it settles.
Three live simulators — watch a match get optimized, a race get resolved, and a price loop get tamed
What Even Is a Ride-Sharing Dispatch System?
A ride-sharing dispatch system's whole job is simple to say: match someone who wants a ride to someone nearby who can give them one, fast, and at a price that reflects supply and demand right now. That's the entire promise.
Everything below this point is about honoring that promise once both sides of the match — riders and drivers — are moving, arriving continuously, and numerous enough that a match that's locally correct for one rider can still be a globally worse outcome for the city. The query framing (“find the nearest driver”) is the wrong mental model from the start, and the rest of this guide is about why.
What Are We Actually Building?
Before reaching for a geospatial index, it's worth being explicit about what this system is actually on the hook for — the same way you'd scope it out loud in an interview before drawing a single box.
Functional requirements
- Match a ride request to a nearby, available driver
- Keep driver location updated in near-real time
- Show an estimated price and ETA before the rider confirms
- Adjust pricing during high local demand
Explicitly out of scope: payment processing, turn-by-turn navigation, and driver onboarding — each is a separate system this one calls or hands off to.
Non-functional requirements
- Latency: a match found within a few seconds, even at peak
- Availability over consistency for location: a few seconds of staleness is fine, an outage isn't
- Strict consistency for exactly one thing: reserving a driver — a double-booking is a real, user-facing failure
- Horizontal scale by geography: load in one city can't degrade matching in another
That consistency split — loose for location, strict for reservation — is the single decision everything below inherits.
Sizing the Problem
Numbers here are explicit back-of-envelope estimates, not measured production values — the point is to find the one number that actually constrains the design, not to be precise.
Traffic (ride requests)
Live location writes
Index size isn't the problem
The constraint that actually rules the design
The Shape of the System
Before drilling into any one piece, here's the system end-to-end: a rider's request reaches the matching service, which searches a geospatial index kept fresh by a constant stream of driver location updates, and returns a matched driver. The API contract and data model below are what every later section refines — nothing past this point replaces this picture, it only explains why each piece of it exists.
Location ingestion keeps the index fresh independently of matching — hover a node
The “Geospatial Index” box is a cluster, not one node. Driver locations are keyed by a geohash prefix — length 6 works out to roughly 1.2km × 0.6km cells, small enough for a useful “nearby” search — and each prefix is assigned to a shard by consistent hashing, so a lookup for one neighborhood only touches one or two shards. That's the piece that actually absorbs the ~250,000 writes/second from the capacity estimate; no single node has to.
Rider
Driver
Ride
DriverLocation / Zone
DriverLocation is deliberately not a field on Driver — different write pattern, different store
Three different write patterns, three different stores. DriverLocation is overwritten every few seconds for a million drivers — the sharded in-memory geo index from above, TTL'd, no durability needed since a stale entry just gets overwritten next update. Ride is the opposite: infrequent, high-value state transitions that need ACID guarantees, so it lives in a relational store where every transition is kept as an immutable event — support and disputes need to reconstruct exactly what happened to a specific ride. Zone is small, changes rarely, and is cheap to cache in full on every matching-service instance.
The Query You'd Reach For First
GEOADD/GEOSEARCH use under the hood, but a driver just across a cell boundary is invisible unless you also check the 8 neighboring cells. A quadtree — cells that shrink where drivers are dense and stay large where they're sparse — handles uneven density (downtown vs. suburbs) better, at the cost of a mutable tree instead of a flat key lookup. Either way, a request that used to touch a million rows now touches a handful of cells.Matching in Batches, Not One Request at a Time
A constructed scenario, not measured data: Rider 1 and Rider 2 both want Driver 1 — Rider 1 would be almost as happy with Driver 2, but Driver 2 is a bad match for Rider 2. Watch what each strategy does with that.
Press “Send 4 requests” to run the scenario.
The simulator solves its 4-rider batch exactly, by brute force, to make the point clearly. Real batches during a surge can have thousands of riders and drivers in one region, and the exact solution (the Hungarian algorithm, O(n³)) gets too slow to run inside a 2-3 second window at that size — production systems fall back to a faster approximate assignment (greedy on sorted distances, or a bounded local-search heuristic) that captures most of the benefit without the cubic cost.
The Double-Booking Race
Both riders' requests hit the geospatial index within milliseconds of each other and both land on Driver Alex as the closest available match.
How Surge Pricing Can Turn Unstable
An event just ended: demand jumps well above nearby supply at tick 0. Each bar is one recalculation tick — watch how the multiplier responds to drivers reacting to last tick's price.
When a Node, a Batch, or a Region Fails
Geospatial index node loss
Matching service crash mid-batch
Ride state store failure
Regional partition isolated from the rest
The pattern mirrors the data model split: ephemeral, self-healing location data can tolerate loss because it's constantly being refreshed anyway; durable ride state cannot, and is engineered accordingly.
What to Watch, and Where Trust Breaks Down
Time-to-match (P50/P99)
Location ingestion lag
Match-then-cancel rate
Surge price volatility, per zone
Driver-submitted location is a self-reported signal, which means it can be spoofed — a driver claiming to be in a high-surge zone they're not actually in is a real abuse pattern, worth cross-checking against plausible movement speed between consecutive updates. Location data is also sensitive personal information for both riders and drivers; access to raw location history should be scoped tightly, and retention of precise historical pings minimized once a ride is complete rather than kept indefinitely by default.