Design a ride-sharing service like Uber
Ride sharing needs live location, fast nearby-driver search and reliable trip state. We design the matching core.

Goal: riders request a ride; the system finds a nearby available driver, tracks the trip and charges the fare.
Requirements
- Drivers report their location continuously.
- A rider requests a ride and is matched with a nearby driver within seconds.
- Live tracking of the trip for rider and driver.
- Reliable trip state and payment.
Estimates
Say 1 million active drivers sending a location every 4 seconds: about 250,000 location updates per second. This is write-heavy and the data is short-lived, so we don't need every point forever.
Location ingestion
Drivers' apps send updates through a gateway into a fast in-memory store (Redis or similar) holding only the latest position per driver. Older points can stream to a log (Kafka) for analytics and trip history, off the hot path.
Finding nearby drivers: geospatial index
Scanning all drivers is too slow. Divide the map into cells:
- Geohash or S2/H3 cells: each location maps to a cell ID. Drivers are indexed by cell.
- A rider's request looks at their cell and the neighbouring cells, then ranks the candidates by distance or estimated arrival time.
Redis supports geospatial queries directly (GEOSEARCH), which is a good starting point.
Matching
- Rider requests a ride (pickup, drop-off).
- The matching service gets candidate drivers nearby and available.
- It sends an offer to the best driver, with a short timeout. If declined or ignored, it moves to the next.
- On accept, it locks the driver so they can't be assigned twice, and creates the trip.
The "one driver, one trip" rule needs care: use an atomic operation or lock on driver state to avoid double assignment.
Trip state machine
Trips move through states: REQUESTED -> ACCEPTED -> ARRIVED -> IN_PROGRESS -> COMPLETED (or CANCELLED). Store state transitions in a reliable database, and make transitions idempotent since apps retry on bad networks.
Live tracking
Push driver location to the rider over WebSocket or SSE during the trip. Update every few seconds, not every GPS tick.
Pricing and payment
Fare from distance, time and demand. Surge pricing raises prices in cells where requests exceed available drivers. Charge at trip end through a payment service with idempotency keys.
Scaling
Partition by city or region. A city's drivers and riders rarely interact with another city, which makes sharding natural.
Takeaway: keep only the latest driver positions in memory, index by geo cells, match with a locked offer flow, and model the trip as an idempotent state machine.
System Design series, Part 3 (case studies): 6 of 16. Previous: Design a video streaming service like YouTube.


