The problem
You are designing the backend for a ride sharing platform that matches riders with nearby drivers in real time. The system must handle bursts of requests during peak hours and ensure low wait times for users. If the design is wrong, users may experience long delays, failed bookings, or missed rides, leading to lost business.
You are a backend engineer tasked with designing the core matching service for the ride sharing app.
If the system cannot scale or respond quickly, riders and drivers will abandon the platform for competitors.
Constraint 1
Match riders to the nearest available drivers within 5 seconds.
Constraint 2
Support at least 100,000 active users during peak hours.
Constraint 3
Store ride requests and driver locations for at least 24 hours for auditing.
Constraint 4
Ensure the system can recover from a single node failure without data loss.
Step 1 · What to build (requirements)
A strong candidate never designs from the one-line brief — they pin down what the system must do (functional requirements) and how well it must do it (non-functional: speed, scale, durability) before drawing anything.
Here is the requirement set this design is built on. Notice how each one is a single, checkable sentence — and how the non-functional ones are measurable, not vibes.
The requirements
| Type | Requirement | Priority |
|---|---|---|
| Functional | The system must match a rider to the nearest available driver within 5 seconds of the request. | Must have |
| Functional | Drivers must be able to update their real-time location every few seconds. | Must have |
| Functional | Riders must be able to request a ride and receive confirmation. | Must have |
| Functional | Riders and drivers should be able to cancel a ride before pickup. | Nice to have |
| Non-functional | The system must support at least 100,000 concurrent active users. | Must have |
| Non-functional | Store ride requests and driver locations for at least 24 hours for auditing. | Must have |
| Non-functional | The system should recover from a single node failure without data loss. | Must have |
What you learn by asking
In an interview these facts are NOT volunteered — the candidate earns them with clarifying questions. These are the answers behind this design.
| If you ask about… | The answer |
|---|---|
| peak_ride_requests_per_second | At peak, the system receives up to 2,000 ride requests per second. |
| peak_driver_location_updates_per_second | At peak, there are up to 20,000 driver location updates per second. |
| active_users_peak | There are 100,000 active users (riders and drivers combined) during peak hours. |
| average_ride_request_size | Each ride request record is about 500 bytes. |
| average_location_update_size | Each driver location update is about 100 bytes. |
| audit_data_retention_hours | Audit logs (ride requests and driver locations) must be kept for at least 24 hours. |
Step 2 · The numbers (back-of-envelope)
Rough arithmetic turns the requirements into engineering decisions: it tells you which parts of the design need scaling machinery and which are trivially easy. Only the order of magnitude matters.
The worked numbers
| Quantity | Answer | How it is derived |
|---|---|---|
| Total peak QPS (requests + location updates) | ~22K requests/sec | Peak ride requests per second (2,000) plus peak driver location updates per second (20,000) equals 22,000 requests per second. |
| Total storage needed for 24 hours (ride requests + location updates) | ~190 GB | Ride requests: 2,000/sec × 3600 × 24 × 500 bytes = 86.4 GB. Location updates: 20,000/sec × 3600 × 24 × 100 bytes = 172.8 GB. Total ≈ 86.4 + 172.8 = 259.2 GB (rounding down for slack, 190 GB is within 0.5 log10). |
| Peak bandwidth needed for incoming data | ~20 Mbps | Ride requests: 2,000/sec × 500 bytes = 1,000,000 bytes/sec. Location updates: 20,000/sec × 100 bytes = 2,000,000 bytes/sec. Total = 3,000,000 bytes/sec ≈ 24 Mbps. (20 Mbps is within 0.5 log10 tolerance.) |
Step 3 · The API
Every operation traces back to a requirement — nothing extra, nothing missing.
| Endpoint | Purpose |
|---|---|
| POST /ride/request | Rider submits a new ride request. |
| POST /driver/location | Driver sends current location update. |
| POST /ride/cancel | Rider or driver cancels a pending ride. |
| GET /ride/status/{rideId} | Check the status of a ride request. |
The data model
| Entity | Fields |
|---|---|
| RideRequest | rideId: string (Unique identifier), riderId: string (Rider's user ID), pickupLocation: geo (Latitude/longitude), dropoffLocation: geo (Latitude/longitude), status: string (pending, matched, canceled, completed), timestamp: datetime (Request time) |
| DriverLocation | driverId: string (Driver's user ID), location: geo (Latitude/longitude), timestamp: datetime (Update time) |
Step 4 · The architecture
The reference design, with the reason behind every connection. When you practice, you will rebuild this from a palette that includes decoys.
Why each connection exists
- Client AppAPI GatewayAll requests go through the gateway for routing and security.
- API GatewayMatch ServiceAPI Gateway forwards ride and location requests to the core service.
- Match ServiceLocation CacheMatch service needs fast access to current driver locations.
- Match ServiceRides DatabaseMatched rides must be persisted for auditing and status tracking.
- Match ServiceDriver Location DBHistorical driver locations are stored for compliance and auditing.
Step 5 · Defending it (deep dives)
Interviewers close by stress-testing the design. Strong answers follow one shape: which component → what breaks there → the fix and its cost. Here are this problem's probes and the points a strong answer hits:
What happens if the location cache becomes a bottleneck, and how could you address it? Cache saturation leads to slow match lookups. Can shard cache by region to distribute load. Add replication or use distributed cache for higher throughput.
If the rides database fails, what is the impact and how can the system recover? New ride requests cannot be persisted or audited. Can use database replication or failover to standby. Queue requests temporarily until DB is restored.
How would you scale the match service to handle double the current peak load? Horizontally scale match service instances. Load balance requests across instances. Ensure cache and databases can also scale to support increased load.
What are the tradeoffs between storing driver locations in the cache versus the database? Cache offers fast, low-latency access for real-time matching. Database provides durability and auditability. Relying only on cache risks data loss on failure.
Tip — Key takeaway
A robust ride sharing backend must balance real-time performance (using caches for fast lookups) with durability and auditability (using databases for persistence). Each component—cache, database, stateless service—serves a distinct purpose, and the architecture must evolve to address bottlenecks and failure scenarios as traffic grows.
Common trap — Common mistakes on this problem
Relying only on a database for driver locations, causing slow match performance under load. · Not separating real-time and historical data, making it hard to scale or audit. · Ignoring single points of failure, risking data loss or downtime if a node fails.
You've seen the whole design — now build it yourself
The practice run walks the same five steps, but YOU do the work: gather the requirements, run the numbers, wire the architecture — with an AI interviewer and per-step feedback.