Ride Sharing Service
IntermediateOverview
A ride-sharing service matches riders requesting trips with nearby available drivers, then tracks the trip in real time until completion. The core challenges are ingesting a continuous stream of driver location updates and answering low-latency geospatial "nearest driver" queries at city scale.
Functional Requirements
- Riders request a ride from a pickup to a destination; the system matches a nearby driver.
- Drivers continuously report their location and availability.
- Track the trip in real time and update both parties (driver en route, in progress, complete).
- Compute fare estimates and finalize payment at trip end.
Non-Functional Requirements
- Low latency: matching should complete within a few seconds.
- High availability: the matching and tracking paths must stay up regionally.
- Accurate, fresh location data with frequent updates.
- Consistency for trip state transitions (a trip has exactly one assigned driver).
Capacity Estimation
Assume 10M active drivers, each sending a location update every 4 seconds, and 5M rides/day.
- QPS:
- Location updates: 10M / 4 s = 2.5M updates/sec - the dominant write load.
- Ride requests: 5M / 86,400 s ~ 58 requests/sec (peak ~10x ~ 580/sec).
- Storage:
- Live locations are mostly hot state in memory: 10M x ~100 B ~ 1 GB resident.
- Trip records ~ 1 KB each: 5M x 1 KB = 5 GB/day -> ~1.8 TB/year of durable trip history.
- Bandwidth: location ingress 2.5M/s x 100 B ~ 250 MB/s; matching/tracking egress is comparatively small.
High-Level Architecture
The system is heavily split between a high-write Location Tracking Service (managing driver pings in memory) and a highly consistent Trip Management Service (managing ride state in a database). An intelligent Dispatch Service connects the two by querying the Location Service for drivers and managing the offer-acceptance flow.
Data Model
| Entity | Fields / Schema | Storage Choice |
|---|---|---|
| driver_location | driver_id, lat, lng, geohash, updated_at, status | In-memory geo index (Redis or custom C++ service), sharded by geohash cell |
| trip | trip_id (PK), rider_id, driver_id, state, pickup, dropoff, fare | Relational / strongly-consistent store (PostgreSQL) |
| driver | driver_id (PK), vehicle, rating | Relational store |
| trip_event | trip_id, ts, event_type, location | Append-only event store (Cassandra) |
Detailed Design
Location Ingest and Geo-Indexing
The 2.5M updates/sec are absorbed by a stateless Location Ingest tier that writes into an in-memory geospatial index (like a Quadtree) partitioned by region. Sharding by geographic cell keeps each node responsible for a bounded region and spreads the write load. Consistent hashing maps cells to nodes so the cluster can grow or shrink. Locations are hot, high-churn state, so they live in memory rather than a disk database, because updating a DB row 2.5 million times a second will destroy the disk.
Matching (The Dispatch Service)
A ride request computes the rider's geohash, queries the Location index for the neighboring cells, gathers candidate drivers, and ranks them by ETA (using a routing engine, not just a straight line). It offers the trip to the best candidate.
State Machine & Consistency
The trip's state transitions (requested -> assigned -> in_progress -> completed) are written to a strongly consistent relational database so a driver is never double-assigned. The Dispatch Service uses optimistic locking when offering a ride to a driver to ensure no other rider claims that driver concurrently.
Bottlenecks & Solutions
Maintaining WebSockets for 10M active drivers to receive real-time dispatch offers is a major bottleneck requiring a massive connection gateway tier. Furthermore, if a stadium lets out, thousands of riders in the exact same geohash will request rides simultaneously, creating a "hot shard" on the Location Index node responsible for that area.