Hotel reservation systems are one of the most discussed system design problems in any engineering interview. In this post, we are going to run through the design of a hotel reservation system like MakeMyTrip, Booking.com etc.
This is a series of posts, the links to each post are:
To begin with, let’s list down the functional requirements. There are 2 sides to the marketplace for which we are building this system. One is the hotel partners and the other is the end customers. On the hotels side, the functional requirements are as follows:
- Onboard a new hotel
- Update details
- Add/update images
- View details
On the customer side, the list of functional requirements would involve:
- Search for hotels in a city/geo-location
- See details of the hotel (room types, charges, availability)
- Create a reservation
- Cancel a reservation
Let’s go through the non functional requirements at this stage:
- The system should be highly consistent on the customer side i.e. a booking which has been created and paid for must reflect immediately on the customer’s view
- On the customer’s side, the system should be able to scale to handle a large number of reads. This is because searching and viewing the restaurant details are the actions that exist at the top of the funnel and we should expect maximum traffic to these 2 flows.
One assumption about the functional requirement that I am making here is that, a customer is not assigned an actual room when a reservation is made. The customer is just reserving a type of room, and the actual room will be allotted when he/she checks in to the hotel. This practical assumption vastly simplifies our data model, which will be described when we model the customer flows.
Let’s start defining the components of the system now.
To cater to the functional requirements for the hotel side of the marketplace, we will need one service possibly named as hotel-admin-service, which will expose the following endpoints:
- POST /hotel — This will onboard/create a new hotel on the platform. The request body will contain the hotel metadata in JSON format.
- GET /hotel/<id> — This will return the consolidated details of the hotel. The response body will contain the hotel metadata in JSON format.
- GET /hotel/images/<id> — This will return the list of image URLs for a hotel ID
- PUT /hotel/<id> — This will update the hotel meta data. The request body will contain the hotel metadata in JSON format.
- PUT /hotel/images — This will add/update the images. The request body will contain a list of image update requests, which an be modelled as follows:
Coming to the database considerations, we could model the data as follows:
Here, the columns marked as red are primary keys.
Some points to consider:
- A hotel can have multiple room types, and each room type can have multiple facilities. Each room type has an attribute called max_num which represents the total number of rooms of that type in a hotel.
- A hotel can upload multiple images to be presented to the customer
- A hotel can have multiple tags which can be used during search.
- A hotel can have multiple contact options like email, phone etc. which are stored in hotel_contact table.
The reason behind going for a relational database in this case is because of the following:
- We can ensure the integrity of data with a relational database using the system and user defined constraints.
- NoSQL databases favour availability over consistency and are generally preferred in case of massive throughputs. We are dealing with a relatively lower scale here (on the hotel side of the marketplace) and hence relational databases should be able to sufficiently scale to handle this workload.
- Using a relational database allows us to extend the system to be used in extended use case. For example, if the company wants to build an internal admin tool which lists all the hotels and lets admin filter and sort on the hotels, we could easily build that with the data model above. However, in case of non relational databases, the query patterns drive the data model.
We can also set up read replicas for our database.
The high level component diagram on the hotel side of the system will look like this:
Here, we have a micro-service called hotel-admin-service that has been described above. It sits behind a load balancer which routes the requests to the containers of the service. On every add or update, the hotel-admin-service publishes a message to the hotels topic on kafka. We will delve more into the consumption off of this topic while working out the customer side of the system. The images that are uploaded to the service are uploaded to the CDN and the reference to the images are stored in the `hotel_images` table that was described in the data model above.
Having the images uploaded to CDN will massively simplify their rendering on the client side, as the clients can download the images from the nearest CDN server and the service itself is abstracted from maintaining the images.
For the sake of simplicity, the above design doesn’t consider any flows related to payments to hotels or commissions. But our data model is extendable to support these use cases too.
This wraps up the hotel side of our system. We will delve into the customer side of the system in the next post. Thanks for reading.