Uber: matching riders and drivers in real time
In the third quarter of 2025 Uber completed about 3.5 billion trips, roughly 38 million a day, for 189 million monthly users. Every one began with the same few seconds: find nearby drivers, estimate how long each would take, and offer the trip to one. This lesson takes those seconds apart and builds the "nearby drivers" part with hexagons.
By the end you can
- Trace a ride request from the app through location index, matching and the offer to a driver
- Explain H3 hexagons and why a ring search finds nearby drivers fast
- Describe how Uber's storage moved from Postgres to Schemaless on MySQL, then Docstore
- Connect Ringpop, Kafka and Cadence to earlier lessons (consistent hashing, events, sagas)
- Build a nearest-driver search with h3-js and Redis, and the Postgres alternative with a GiST index
The everyday picture
Picture the taxi and motorbike stand outside a busy market. A dispatcher stands in the middle with a notebook that divides the area into small blocks: "two bikes at the bank corner, one near the pharmacy, none by the bus stop". A customer comes out of the market with heavy bags. The dispatcher does not search the whole city. He looks at the customer's block first, then the blocks around it, then one ring further out, until he has a few candidates. He does not call the closest one either: the closest might be facing the wrong way on a one-way road. He picks the one who can actually arrive first, and calls him over.
On a festival eve one block has ten customers and no bikes, so the fare there rises until more bikes come. That is Uber: a map cut into cells, a ring search, ranking by arrival time, and prices per cell from supply and demand.
What the product must do
- Functional. Show the rider nearby cars and a price before they book. Accept a request, find a driver, send the driver an offer they can accept or decline, then track the trip live, charge the fare, and pay the driver.
- Non-functional. The match should take seconds. Location must be fresh: a position that is a minute old is a different street. One trip must never get two drivers, and one driver must never get two trips at once. It must keep working when a data centre fails mid-trip, and on drivers' phones with patchy mobile data.
- The hard part. The system state changes every few seconds for every online driver, and the important data (who is where, who is free) is mostly in memory, not in a database row.
Note the mix (CAP and consistency): "which cars are near me" can be seconds stale; "this driver has this trip" must be exact.