1. The Headline
Millions of concurrent location updates per second.
Uber isn't just a web application; it's a massive, real-time geospatial marketplace. The entire business relies on tracking the physical coordinates of millions of moving cars globally, predicting ETAs, and matching drivers with riders in under a second.
2. Requirements and Constraints
Functional Requirements:
- Drivers constantly transmit their GPS location.
- Riders open the app and instantly see nearby cars on a map.
- The system matches a rider's request with the optimal driver based on ETA, not just raw distance.
Non-Functional Requirements:
- High Write Throughput: Millions of drivers updating their location every 4 seconds generates a massive write load.
- Low Latency Reads: A rider's app must query the database and render the map instantly.
- Geospatial querying: Standard SQL
SELECTstatements are too slow for complex radius searches on a sphere.
The Ultimate Constraint: You cannot store a driver's rapidly changing location in a traditional SQL database and query it fast enough to run a matching algorithm. The math required to calculate the distance between two latitude/longitude points (the Haversine formula) is CPU-intensive. Running that math against every row in a database every time a rider opens the app is computationally impossible.
3. The Naive Design & Where It Breaks
A naive approach to finding nearby cars:
- Drivers send their lat/long to a Node.js server via HTTP POST every 5 seconds.
- The server saves the coordinates to a PostgreSQL table
drivers (id, lat, lng). - A rider opens the app and sends their coordinates.
- The server queries Postgres:
SELECT * FROM drivers WHERE lat BETWEEN x AND y AND lng BETWEEN a AND b.
Where this breaks under Uber's load:
- Write Amplification: Updating a PostgreSQL row millions of times a second will destroy the disk via excessive I/O and index fragmentation.
- Query Latency: Bounding-box queries on raw coordinates require full table scans or highly complex B-Tree indexing, which degrades rapidly under heavy write load.
- Battery Drain: If the driver's phone establishes a new HTTP connection every 5 seconds, the overhead of the TCP/TLS handshake will drain the phone's battery in an hour.
4. The Real Architecture: Layer by Layer
Normal operation: The client streams video from the CDN and maintains a persistent WebSocket/MQTT connection for real-time scores.
The Network Layer (WebSockets / gRPC)
To save battery and reduce latency, the Driver App establishes a persistent WebSocket or gRPC stream with the backend (via an API Gateway). The phone batches GPS updates and streams them over this single open connection, completely eliminating TLS handshake overhead.
Geospatial Indexing (H3 & Redis)
Uber open-sourced their solution to the geospatial querying problem: H3. H3 is a hexagonal hierarchical spatial index. Instead of storing raw coordinates, H3 divides the entire globe into a grid of hexagons.
When a driver sends a GPS coordinate, the backend mathematically converts that coordinate into an H3 Hexagon ID (a simple string like 89283082803ffff).
- The backend stores this in an in-memory cache like Redis, mapping the Hexagon ID to a list of Driver IDs.
- When a rider opens the app, their coordinates are also converted to a Hexagon ID.
- The backend instantly queries Redis for all drivers in that Hexagon (and the 6 neighboring hexagons). This reduces a complex spatial math problem to a lightning-fast key-value lookup.
The Matching Engine
Once the backend retrieves the nearby drivers from Redis, it runs a routing algorithm to calculate the actual ETA (accounting for traffic and one-way streets), ranks the drivers, and dispatches the match.
5. The Hard Problem
The "Phantom Car" Problem.
Because GPS is inaccurate (especially in cities with tall buildings causing multi-path interference), a driver's raw GPS ping might jump 50 meters, placing them on the wrong side of a river. If the backend blindly trusts the raw GPS, the rider will see cars jumping erratically across the map.
6. What This Means for the Client (Frontend)
To solve the Phantom Car problem and provide a smooth UX, the frontend client uses heavy local prediction.
Map Snapping & Interpolation
When the Rider App receives the location of a nearby driver, it doesn't just plot the raw coordinates.
- Map Snapping: The client snaps the coordinate to the nearest logical road vector on the map, masking GPS jitter.
- Interpolation: Since the driver only sends updates every 4 seconds, the car on the screen would jump chunkily. The frontend client calculates the car's trajectory and animates a smooth interpolation between the last known point and the current point, creating the illusion of smooth, real-time movement.
Location Batching
On the Driver App, constantly querying the GPS chip and sending network requests is expensive. The client batches location updates locally and sends them in small bursts, carefully managing the radio antenna to preserve battery life.
7. Failure Modes & Graceful Degradation
- Cache Failure: If the Redis instances holding the real-time locations crash, the system falls back to a persistent datastore (like Cassandra), though matching latency increases.
- Degraded ETA: If the complex routing engine fails, the system falls back to calculating raw straight-line (Haversine) distances to keep the core matching functionality alive, even if the ETAs are slightly less accurate.
8. Numbers & Tradeoffs
- Architecture: Hexagonal Spatial Indexing (H3) over in-memory key-value stores.
- Tradeoff: Using a grid system like H3 introduces slight inaccuracies at the edges of the hexagons compared to raw spatial math. However, the tradeoff of absolute precision for O(1) lookup speed is necessary to operate at global scale.
9. How to Use This in an Interview
If an interviewer asks you to design a location-based service (like Yelp, Tinder, or a delivery app):
"For geospatial querying, raw SQL coordinates are too slow. We should use a spatial indexing system like Geohash, S2, or Uber's H3. By converting lat/long into a string representation of a grid cell, we can use an in-memory cache like Redis to find nearby entities in O(1) time."
"To optimize the mobile client, we shouldn't send HTTP requests for every location update. We should use a persistent WebSocket connection and batch the GPS updates locally on the device to save battery and reduce network overhead. The receiving client can use interpolation to mask the batched updates and render smooth movement."
10. Sources
- Uber Engineering: H3: Uber’s Hexagonal Hierarchical Spatial Index
https://www.uber.com/en-IN/blog/h3/ - Scaling Uber's Real-time Market Platform
https://www.uber.com/en-IN/blog/uber-realtime-market-platform/