System Design Arena
System Design: Ride-Hailing Service (like Uber)
Use an interview-style checklist to reason through matching, geo-spatial indexing, surge pricing, and operational metrics.
Case Study
Ride-Hailing Service
Same conversation, diagrams, and wrap-up you expect—now framed with clearer scaffolding and iconography.
Prompt
Build a marketplace that pairs riders with nearby drivers while streaming live locations, computing surge, and settling payments globally.
Interview snapshot
- • Topic: Ride-Hailing Service
- • Expected depth: 45 - 60 minutes
- • Focus areas: APIs, scale estimation, resilient architecture
- • Wrap-up: risk, monitoring, disaster recovery
Key takeaways
- • Rider app: request, cancel, share trip, rate driver.
- • Location latency < 3 s; ride assignment < 2 s.
- • POST /api/rides - rider request with pickup/dropoff, preferences.
🎙️ Interview mode
Practice this like a real interview
Don't read the answer first. Work the framework against the bare prompt, then compare against what the interviewer expected at each step.
Scorecard
What the interviewer is evaluating
Staff-level signal
Does the candidate recognize that matching is a geospatial streaming problem with a freshness deadline — and design the location pipeline before drawing any services?
🧠 Staff engineer judgment
Driver locations are ephemeral — losing 30 seconds of them is harmless. Do not design durable storage for data whose value expires in 4 seconds.
Calibration
The common (bad) answer
Rider app → API → Matching Service → Driver app
↓
Database of drivers❌ Why this scores poorly: Treats matching like a database query. With 1M drivers updating location every 4 seconds, "SELECT nearest driver" against a table is dead on arrival.
✓ What a strong answer adds
- Size the location firehose first: drivers × update rate = the real design constraint.
- Use geo-indexing (geohash/S2 cells) held in memory, not a relational table.
- Separate the always-on location stream from the request/response trip lifecycle.
- Explain surge/matching as an eventually-consistent view — riders see ~4-second-old truth.
- Design the trip state machine with idempotent transitions for retries.
Build it up
Step-by-Step Walkthrough
Ride-hailing is a moving-data problem: both sides of the marketplace are GPS dots that will not sit still. Build it up in stages and narrate why each piece exists.
Naive matching: query all drivers
Rider requests a trip; the server scans the drivers table for anyone nearby, picks the closest, done. With ten drivers in one city this is fine.
The bottleneck is obvious the moment you say it: “find nearby” over raw lat/lng columns is a full scan, and driver positions change every few seconds, so the table is also write-hot.
Index space itself: geohash / H3 cells
Divide the map into cells (geohash prefixes or Uber's H3 hexagons). Drivers are bucketed by the cell they are in; “nearby” becomes “this cell plus its neighbors” — a handful of key lookups instead of a scan.
Keep this hot index in memory (Redis), not the database: it is rebuilt continuously from location pings and loses nothing important if it restarts.
?Why hexagons come up
Squares have neighbor-distance asymmetry (corner neighbors are √2 farther). Hexagons make “adjacent cell” mean roughly the same distance in every direction — which is why H3 exists. Mentioning this earns real credit.
Make dispatch a stateful conversation
Matching is not a query, it is a negotiation: offer the trip to the best driver, wait ~10 seconds, cascade to the next on decline. That state machine needs somewhere durable to live so an instance crash does not orphan a rider.
Trip state (requested → offered → accepted → in-progress → completed) goes to a transactional store; the offer timers and cascade logic live in the dispatch service.
Surge, ETAs, and the read fan-out
Pricing needs supply/demand per cell (computed from the same geo index), ETAs need a routing engine over road-network data, and riders watching the car crawl toward them generate a huge stream of location reads.
Location fan-out to watching riders goes over persistent connections (WebSocket/gRPC streams) fed by the location service — never by polling the trip store.
!The consistency trap
Do not promise strong consistency on locations — stale-by-two-seconds is fine everywhere except payment and trip state. Splitting the system by consistency need (transactional trips vs. streamed locations) is the senior signal.
Blueprint
Architecture Diagram
The narrated components above, laid out as an actual flow — so you can see how a request moves through the system, not just read a list of pieces.
Ride Request
Clients
rider + driver apps
API Gateway
WebSockets terminate at regional real-time clusters
Location Ingest
Location Ingest Service
writes to GeoRedis/S2 index
Kafka
publishes for analytics/surge pricing
Matching
Matching Service
consumes rider requests
Bipartite Match
pairs against driver availability
Ride State Machine
Temporal / Cadence
workflow engine drives ride state machine + timeout handling
Payments
Payments Service
interacts with PCI vault, ledger
Payout System
settles driver earnings
Flow Diagram
How the API maps to this flow
- 1
POST /api/rides— rider request with pickup/dropoff, preferences. - 2
POST /api/rides/{id}/accept— driver confirms, locking the ride. - 3
POST /api/locations— batched driver GPS updates. - 4
POST /api/rides/{id}/complete— marks ride finished, triggers billing. - 5
GET /api/rides/{id}/tracking— rider fetches state when sockets unavailable.
?But why does this actually hold up at scale?
5M DAU -> 833K location updates/sec globally; sharded by city reduces to ~167K/sec shard.
Video walkthrough
Design Uber — System Design Interview breakdown
Hello Interview · ex-Meta staff engineer · 1h 3m
Matching and geospatial indexing done at interview pace, with the trade-offs argued out loud.
Work the prompt yourself first — guided practice grades your own answer step by step. Watching someone else design it feels like progress and teaches you far less.
Interview flow
Dialogue timeline
Interviewer
What flows must we support?
Candidate
Rider requests, driver accepts, turn-by-turn tracking, payment capture, driver payout. Also pooled rides and cancellations.
Interviewer
Where does scale bite first?
Candidate
Location ingest. 1M drivers pinging every few seconds -> hundreds of thousands of writes/sec into a geo index.
Interviewer
Walk me through matching.
Candidate
Rider request hits marketplace service, which queries nearby drivers via S2 grid in Redis, scores them, and pushes offers over WebSockets. A workflow engine tracks ride state.
Interviewer
How do you keep payments and compliance sane?
Candidate
Payments microservice talks to PCI vault, stores minimal tokens, emits ride receipts, and enforces data residency by region. Events flow to a ledger service for auditing.
Scoping
Requirements & trade-offs
Functional Requirements
- —Rider app: request, cancel, share trip, rate driver.
- —Driver app: toggle availability, accept/decline, navigate, receive payouts.
- —Marketplace: nearest-driver matching, ETA recalculation, surge pricing.
- —Payments: capture fares, tips, refunds, settlements to driver wallet.
Non-Functional Requirements
- —Location latency < 3 s; ride assignment < 2 s.
- —Availability 99.95% with graceful degradation (fallback SMS updates).
- —Strong observability: replay ride timeline, detect fraud, capture audit trail.
- —Regional compliance: data residency (EU vs US), receipts retained 7+ years.
Blueprint
Architecture modules
Module 1
API Endpoints
- •POST /api/rides - rider request with pickup/dropoff, preferences.
- •POST /api/rides/{id}/accept - driver confirms, locking the ride.
- •POST /api/locations - batched driver GPS updates.
- •POST /api/rides/{id}/complete - marks ride finished, triggers billing.
- •GET /api/rides/{id}/tracking - rider fetches state when sockets unavailable.
Module 2
Back-of-the-Envelope
- •5M DAU -> 833K location updates/sec globally; sharded by city reduces to ~167K/sec shard.
- •Ride requests peak 50K/sec; need stateless API tier with autoscaling.
- •Driver presence: 1M drivers * 2 KB session ~ 2 GB in memory/Redis.
- •Kafka topic for telemetry sized for 1M msgs/sec (3 brokers * 3 replicas).
Module 3
System Diagram Notes
- •Clients -> API gateway; WebSockets terminate at regional real-time clusters.
- •Location ingest service writes to GeoRedis/S2 index + publishes to Kafka for analytics/surge.
- •Matching service consumes rider requests + driver availability to run bipartite matching.
- •Temporal/Cadence workflow drives ride state machine + timeout handling.
- •Payments service interacts with PCI vault, ledger, payout system.
- •Analytics lake stores immutable ride events for ML and finance.
Module 4
Design Playbook
- •Clarify SLAs (booking time, ETA accuracy).
- •Define data models: driver session, rider request, ride event log.
- •Explain geospatial indexing + fallback when cells sparse.
- •Cover failure scenarios: driver drops offline, duplicate charges, surge spikes.
- •Discuss monitoring: city-level supply/demand, fraud signals, payments reconciliation.
- •Wrap with DR strategy: active-active for marketplace, active-passive for PCI zone.