Guide

A ride-sharing dispatch system matches a rider who wants a trip with a nearby driver who can take it. The hard parts are not the fare screen. They are three things: ingesting location updates at very high write rates, finding "who is nearest?" quickly, and handing each trip to exactly one driver when many riders compete for the same drivers.

This case study builds the core first: the location pipeline and exclusive assignment. Pricing, ETAs and pooling are add-ons to a correct match.

Requirements

Functional. Riders request a trip with a pickup, a drop-off and a product type. Drivers stream their location while online. The system matches a driver within seconds, shows an ETA, and supports cancellation and reassignment. A trip moves through its states until it is paid.

Non-functional. Locations must be fresh within a few seconds. Matching should finish in seconds at the product level. Two riders must never get the same driver for overlapping trips. City hot spots, such as airports and stadiums, must not overload any one shard.

Estimates

Drivers online in a large region: about 1,000,000
Location update interval:         every 4 seconds
Location writes: 1,000,000 ÷ 4 = 250,000 updates per second

Ride requests: thousands per second at most, far fewer than location writes

Location ingestion dominates the write rate. A store that updates one database row per ping, every 4 seconds, for a million drivers will not keep up. The matching path needs the latest position in memory. Historical GPS data can go to a stream and then to cold storage.

How it fits together

Here is the timeline of one trip, with the ideas from each concept page:

t=0.0 s   Rider POST /trips (idempotent) → trip is searching
t=0.1 s   Matcher reads the cells around the pickup, gets 15 drivers
t=0.3 s   ETA ranks the drivers; a compare-and-set claim on driver D succeeds
t=0.4 s   Offer pushed to D; trip is offered
t=8.0 s   D accepts → trip is accepted; rider is updated; D leaves the available set
t=…       D arrives → in progress → completed → payment (idempotent charge)

If D never answers, the claim expires after about 15 seconds. The matcher then offers the trip to driver E, and so on, until a maximum radius or timeout returns "no drivers".

The concepts that build this are:

StepConceptWhat it answers
1Geospatial indexesHow do you find drivers near a point quickly?
2Driver location ingestionHow do 250,000 updates per second reach the index?
3Exclusive driver assignmentHow does one driver go to one rider?
4Trip state machineHow is a trip's state kept correct, from request to payment?
5Geo sharding and hot spotsHow do you partition by city and handle an airport surge?

Failure modes

FailureMitigation
Location lagShow a stale warning, widen the search, and skip drivers with old timestamps
Matcher crashes mid-offerLease timeouts free the driver automatically
Index memory is lostRebuild from the last stream offsets and driver reconnect snapshots
City hot spotDedicated capacity, honest waits, and surge pricing
Routing service is downFall back to straight-line distance with padding, and keep matching

Surge pricing

Surge pricing is a control loop on aggregates, not on the rider's critical path. Each cell records requests per minute, available drivers and average wait. A multiplier is computed from the demand-to-supply ratio, with caps and hysteresis so prices do not thrash. The trip request reads the current multiplier for its pickup cell. Drivers' heat maps come from the same aggregates.

Later extensions

Carpool pooling is a richer optimization problem on the same location index. Safety features, such as trip sharing and emergency buttons, consume the same trip ID and location stream, so they should not block matching. Observability should trace one trip ID across the matcher, the driver's acknowledgement and the payment.

Common mistakes

  • Storing every location ping in a row-based database. The write rate outruns the store.
  • Matching with stale positions. Check the timestamp before you offer a trip.
  • Ignoring the claim. Without it, two riders can book the same driver.

Key takeaways

  • Location writes dominate, so keep an in-memory geo index fed by a stream.
  • Use cell-based searches, such as H3 rings, to find nearby drivers.
  • Exclusive assignment needs an atomic claim with an expiry, not a hope.
  • Model trips as an explicit state machine, stored separately from the location index.
  • Partition by geography, and plan for airports and stadiums.

Further learning

Uber's H3 documentation is the reference for the hexagonal index this design uses:

H3: Uber's hexagonal hierarchical spatial indexH3h3geo.org ByteByteGo blog (Alex Xu)Explain complex systems with simple terms, from the authors of the best-selling system design book series. Join over 1,000,000 friendly readers. Click to read ByteByteGo Newsletter, a Substack publication.blog.bytebytego.com

A walkthrough of real-time routing and dispatch, including hexagonal indexing and the location write flood:

System Design Interview: Uber's Real-Time RoutingJett Space

Start with geospatial indexes to see how a location becomes a lookup.