Design Uber (Ride Sharing)
DifficultyHard | HelloInterview: problem breakdown
Problem Statement
Design a ride-sharing platform where riders can request rides and drivers can accept them. The system must match riders to nearby available drivers in real time and provide live location tracking.
๐Real-world: Uber's defining technical problem is geospatial indexing at scale โ efficiently answering "which drivers are near this rider?" across millions of constantly-moving GPS points. Their answer became H3, the open-source hexagonal grid system they built and released, which (along with geohashes and quadtrees) is the heart of this design. The security/trust angle is unusually rich here: Uber's 2016 breach โ attackers found AWS credentials hardcoded in a private GitHub repo and stole 57M riders'/drivers' data โ became infamous because Uber paid the attackers $100K through its bug-bounty program to stay quiet and called it a "bug bounty," leading to a criminal conviction of its security chief for obstruction. It's the canonical cautionary tale for secrets-in-source and breach cover-ups โ a perfect thing to reference when the interviewer asks about securing the driver/rider data this system stores.
Requirements
Functional
- Rider requests a ride with pickup + destination
- System shows nearby available drivers
- Driver accepts / declines rides
- Real-time location tracking (rider tracks driver en route)
- ETA calculation
- Surge pricing
- Ride history
Non-Functional
- 15M rides/day globally โ ~170 rides/s average
- Driver location update: every 4 seconds per driver โ 5M active drivers ร 0.25/s = 1.25M location updates/s
- Matching latency: < 3 seconds from request to match
- Global: multiple regions, each city is semi-independent
- High availability: can't afford downtime during peak hours
Core Design
The Two Core Challenges
find all drivers within N km of the rider in real-time, with locations updating continuously
select the best available driver and dispatch (bidding or assignment algorithm)
Geo-Index: Geohash
Geohashencodes a lat/lng into a base-32 string. Adjacent strings share a common prefix. Resolution scales with string length.
lat=37.7749, lng=-122.4194 (San Francisco)
Geohash length 6: "9q8yy2" โ ~1.2 kmยฒ cell
Geohash length 5: "9q8yy" โ ~4.8 kmยฒ cell
To find nearby drivers:
1. Hash rider's location โ geohash prefix
2. Include 8 neighboring cells (handles cell boundary problem)
3. Query Redis: GEOSEARCH or SET of driver IDs per geohash cellAlternativeQuadtree โ recursive spatial partition. More efficient for uneven density (more cells in NYC than Montana). More complex to implement.
Production choiceUber uses S2 library (Google's spherical geometry library) which uses space-filling Hilbert curves. Redis GEO commands (GEOADD, GEORADIUS) use geohash internally.
Driver Location Store
Driver locations update every 4s. Need to:
- Accept 1.25M writes/s
- Query: "all drivers within 5km of (lat, lng)"
Redis (in-memory, per-region cluster):
Key: "drivers:{geohash_prefix_5}"
Value: sorted set of { driver_id: encoded_lat_lng }
TTL: 30s (remove offline drivers automatically)
On each driver update:
ZREM old_geohash_key driver_id
ZADD new_geohash_key score(lat_lng) driver_id
EXPIRE both keys 30sAlternatively, use Redis GEOADD + GEORADIUS which handles this natively.
Architecture
Driver App โ Location Service โ Redis (geo-index, per region)
โ
Rider App โ Matching Service โ query nearby drivers from Redis
โ
Dispatch Service โ assign driver
โ
Trip Service (Postgres) โ create trip record
โ
Notification Service โ push to driver + rider
โ
Tracking Service (WebSocket) โ live location during tripMatching Algorithm
1. Rider submits pickup location
2. Matching Service โ query Redis for drivers in geohash cells around pickup
3. Filter: available=true, rating >= threshold, vehicle_type matches
4. Rank by: (distance * weight) + (acceptance_rate * weight) + (driver_score * weight)
5. Top N candidates โ send ride request notification (parallel)
6. First to accept โ assigned; others โ cancelled
7. If no accept in 10s โ expand search radiusSurge Pricing
surge_multiplier = f(demand / supply)
demand = active ride requests in area in last 5 min
supply = available drivers in area
Zones: geohash cells aggregated into pricing zones
If demand/supply > threshold โ increase multiplier
Display to rider before confirmationKey Design Decisions
| Decision | Choice | Reason |
|---|---|---|
| Geo-index | Redis with geohash | In-memory speed; handles 1.25M writes/s |
| Location updates | Write-through to Redis only | Don't need historical location on every update |
| Driver status | Redis (in-memory) | Must be fast; lost on restart is OK (drivers reconnect) |
| Trip data | PostgreSQL | ACID transactions; historical queries |
| Real-time tracking | WebSocket | Bidirectional, low-latency location push |
| Regional architecture | Per-city/region clusters | Ride matching is local; global coordination not needed |
ETA Calculation
Simple approach: distance / average_speed_for_area_and_time_of_day (historical data).
Production: integrate with mapping API (Google Maps, HERE) for real road network routing with real-time traffic.
Security Considerations
| Threat | Mitigation |
|---|---|
| Location spoofing by driver | GPS verification; speed sanity checks (can't go 300km/h); phone sensor validation |
| Fake driver profile | Government ID verification at onboarding; biometric check-in |
| Rider tracking abuse | Location only shared during active trip; blur precise location for finished trips |
| Payment fraud | 3DS2 for card verification; fraud ML model; velocity checks |
| Trip manipulation | Server-side trip validation; driver cannot report impossible routes |
| Privacy of location history | Location data encrypted at rest; strict retention policy; GDPR compliance |
| Driver impersonation | Unique in-app QR code for rider to verify driver identity |
| Surge manipulation | Anomaly detection on requests that may be fake to trigger surge |
Interview Tips
know both, explain the trade-offs, and say production systems often use S2 or dedicated geo-index.
this number surprises people. Redis handles it because writes are O(log N) on sorted sets, and each Redis node can do 100k+ ops/s.
a rider at the edge of a geohash cell might miss a driver just outside the cell. Solution: always query neighboring cells too.
is a system design question in itself โ demand/supply ratio per zone, real-time computation.
is worth drawing: requested โ accepted โ en_route โ arrived โ in_progress โ completed โ rated.