Uber
AP(Avilable, Partition Tolerant). eventual consistent is
fine.read heavy system
There are 2 entities in system:
- Driver(who updates his location(lat,long) in system).
- User(Customer) who gets nearby(within 10 lm radius) drivers based on
his location(lat,lon)
Requirements
Functional:
User(Customer)/Driver should be able to create profile
Driver should be able to add/update their location
User should be able to check rides, make booking, cancel
booking
User should be able to pay
Non-Functional: Available, Fault tolerant, Scalable
All requirements are around CRUD(create, read, update, delete)
BOE
Assumed. Users(300 Million) Drivers(1M). DAU(1M), DA Drivers(500k).
Daily rides(1M) Drivers update their location every 5 seconds.
QPS (Queries Per Second)
User Queries: 1M / 86400 = 12 queries per second
Driver does not do queries, but updates are pushed to driver when
driver is not on trip.
Bandwidth Estimates
1 User Requests for cab location size = 90 bytes. 12 x 90 = 1080
bytes/sec
TCP, IP, DL Header sizes.
|App Hdr + (userlong, lat, userId, preference)|Transport TCP(src,dst port)|NW(src, dst IP)| DL Hdr(src, dst MAC) |
20bytes 17bytes 20 bytes 20 bytes 14 bytes => 90bytes
HLD
QuadTree
QuadTree to store driver location(lat, long) and to effectively user App
query nearby 10km radius drivers.
We will extend
quadtree design
of yelp here
Frequent Updates on quadtree:
Difference b/w Uber & yelp is there would be more frequent updates on
quadtree wrt yelp. Since Drivers update their location(driver_id, lat,
long) every 5 seconds, Will we update quadtree on every update?
No. We will create a local datastructure(Hash Table), which will
store info of drivers and will send the information after 10-15 seconds.
This will reduce frequent updates on system.
Hash Table:
key=driver_id(3 bytes), value={lat(8bytes), long(8bytes)} //19 bytes
500k driver. 10Mbytes of storage
System Blocks
%%{init: {'themeVariables': {'fontSize': '13px'}, 'sequence': {'actorMargin': 45, 'messageMargin': 30, 'boxMargin': 8, 'useMaxWidth': true}}}%%
flowchart LR
%% Clients
Customer["Customer App"]
Driver["Driver App"]
GLB["Global Load Balancer"]
RLB["Regional Load Balancer"]
AZLB["AZ Load Balancer"]
APIGW["API Gateway"]
UserService["User Service"]
RideService["Ride Service"]
LocationService["Location Service"]
PaymentService["Payment Service"]
UserDB[(User DB)]
RideDB[(Ride DB)]
PaymentDB[(Payment DB)]
LocationCache["Redis Cache"]
QuadTree["QuadTree / Geospatial Index"]
Kafka["Kafka"]
MatchingService["Ride Matching Service"]
NotificationService["Notification Service"]
AnalyticsService["Analytics Service"]
SurgePricing["Surge Pricing Service"]
%% Entry
Customer --> GLB
Driver --> GLB
GLB --> RLB
RLB --> AZLB
AZLB --> APIGW
%% Core Services
APIGW --> UserService
APIGW --> RideService
APIGW --> LocationService
APIGW --> PaymentService
%% Databases
UserService --> UserDB
RideService --> RideDB
PaymentService --> PaymentDB
%% Location
LocationService --> LocationCache
LocationService --> QuadTree
%% Async
LocationService --> Kafka
RideService --> Kafka
Kafka --> MatchingService
Kafka --> NotificationService
Kafka --> AnalyticsService
Kafka --> SurgePricing
%% Notifications
NotificationService --> Customer
NotificationService --> Driver
Driver Location update
%%{init: {'themeVariables': {'fontSize': '13px'}, 'sequence': {'actorMargin': 45, 'messageMargin': 30, 'boxMargin': 8, 'useMaxWidth': true}}}%%
sequenceDiagram
autonumber
participant Driver
participant API
participant LocationService
participant RedisCache
participant QuadTree
participant Kafka
participant NotificationService
Driver->>API: POST /location(lat,lng)
Note over API: REST endpoint aware
|
1. Driver sends its location(latitude,longitude) to an API gateway
every 5 minutes. The API gateway is aware about the REST Endpoint
and it sends the location to the location service. 3. The location service checks the cache that if this driver's location is same as previous. If not, it will not update. 5. Updated driver location in Quadtree. if quadtree node becomes heavy in Quadtree that is broken into sub quadtrees |
User/Customer/Rider searches Nearby Drivers
%%{init: {'themeVariables': {'fontSize': '13px'}, 'sequence': {'actorMargin': 45, 'messageMargin': 30, 'boxMargin': 8, 'useMaxWidth': true}}}%%
sequenceDiagram
autonumber
participant Rider as Rider/User/Customer
participant API
participant RideService
participant LocationService
participant Redis
participant QuadTree
participant UserDB
Rider->>API: GET /nearbyDrivers
|
The Notification Service does not participate in the synchronous "find nearby drivers" API because its a Kafka client and rider is waiting for an immediate response, we will not bank on kafka for sending notifications |
kafka Messages
topic= driver-location-updated
|
Consumers: Notification Service, Analytics Service, Surge Pricing Service, Ride Matching Service (optional, depending on architecture) |
APIs (CRUD)
User APIs
-
REST API?
REST API Versioning(v1,v2)
1. User Creates a booking |
2. User gets all nearby cabs |
4. User can cancel the ride |
|---|---|---|
|
|
|
|
|
|