Simran: "Just booked an Uber. It says 3 minutes away."
Raj: "So you are leaving me at the train station?"
Simran (checks phone): "I don't think he is interested. He is driving the other way…"
Raj: "Zindagi ke har mod pe tumhe do raste milenge… (you will find two road's at every turn of life)"
We have all had hilarious experiences with cab booking services, but it's easy to underappreciate the seamless, good matching, and accurate ETAs of these apps.
Through this blog, we will try to unveil the High-Level System Design of Uber’s Trip Booking system, and how it’s helping millions of users book cabs at the tap of a button.
Functional Requirements
- Trip Booking: Enables users to book a ride, specify pick-up and drop-off locations, and choose ride types (e.g., Uber Go, Uber Premier).
- Fare Calculation: Calculates fare based on distance, time, ride type, and local fare rates.
- Route Optimization and Navigation: Provides optimized routes for drivers, considering traffic conditions, distance, and estimated time of arrival.
Non-Functional Requirements
- Performance: The system should handle high numbers of concurrent users and transactions without significant delays or downtime.
- Scalability: Capable of scaling up resources to meet increasing demand without performance loss.
- Reliability and Availability: High uptime, with reliable access to the service at all times.
High-Level Architecture

The high level design of a cab aggregator app
Through the above architecture, we will try to understand the booking system through both, the Customer UI and Driver UI
When the Customer books the cab, the request is received by the Request Service through a Web Socket connection between the service and the user and the request service further sends it to the Search Service to get the best cab available for the user
Search and Location Service
The Search Service is the most crucial part of our system, it is constantly in touch with many other services at one time.
It first connects with the Location Service which has the latest latitude and longitude of the driver and customer
It gets these coordinates from Map Services which is another very important service as it divides typically a large geographical area into smaller chunks and segments.
The location service marks the driver's precise location in those segments and chunks and stores into Redis for fast retrievals.
Location service is also connected to Cassandra to store data like:
- How much distance is between the driver and the customer?
- How much time will it take to reach the customer?
Web Socket Manager
The Search Service is connected to the Web Socket Manager which has three major jobs:
- Notify the driver about the customer who has requested for cab
- If the driver goes offline or denies the request, then notify the web socket manager about it
- Store the mapping of the driver to their web socket handler
Trip Service
The Trip Service is connected to the search service to keep track of all the ongoing trips and trips that are about to happen, all the past trips that have taken place are stored in a NoSQL database like Cassandra during non-peak hours
Analytics
There will be a lot of events published into Kafka and running some analytics on top of it would be extremely beneficial such as:
- Drivers and customers can be matched based on the ratings
- Customers can be upgraded to premium vehicles based on their past ratings
- Distributing the drivers geographically well for better customer experience
- Detecting any fraud in payments or services
After accumulating all the best results the Search Service will reach back to Request Service saying “Hey, here are all the necessary IDs of the Trip, Driver, etc” and the user will be notified about the same via his/her device through an interactive user interface.
Matching in real time: Tradeoffs!
Matching drivers to riders is a critical part of any ride-sharing system. Its algorithm efficiency is a core product differentiator.
Here are things we must consider when matching rides:
- How do we find the nearest driver for a ride request, fast?
- How do we ensure that a single driver doesn't get multiple requests?
- How do we ensure that a single request is not accepted by multiple drivers?
Satisfying all the above points is impossible (1 and 3, for example, are against each other).
Instead, we must settle for tradeoffs with this algorithm:
- On receiving a ride request, we find nearby drivers and choose any one driver who doesn't have an active request.
- While this driver receives and responds to the notification, others wait.
- If the rider accepts, we remove them from the pool of available drivers and mark the request as complete.
- If the driver times out or rejects, we pick the next driver in the pool and try again.
The above algorithm satisfies points 2 and 3. Point 1 (which impacts customer satisfaction) is dampened to ensure the other factors of a ride-sharing app are kept high (driver experience, less confusion, and reduced cancellations).
Conclusion
A cab aggregator app is a mix of product considerations, technical requirements, pricing, and graph algorithms.
We are glad to shine some light on this simple-yet-complex app, and look forward to seeing you in future blogs!
To know more about the Uber Design, go to: Uber Design