Assume
Storage
Requests
// User management and hotel listing management APIs are CRUD APIs are omitted.
// Search API
GET /hotels?location=
// View hotel details
GET /hotels/
// View hotel room details
GET /hotels/
// Book room
POST /reservations -> Reservation
{
id, // output
hotelId,
roomId,
checkinDate,
checkOutDate,
adultNum,
childNum,
}
// Pay for reservation
POST /payments -> Payment
{
id, // output
reservationId,
paymentDetails, // {creditCardNumber, etc}
}
User
Hotel
Room
Reservation
Payment
The core data is relational and needs strong consistency guarantee. We choose a relational database like postgresql, with ES that facilitates searching, and caching (like redis) to make reads more efficient.
ViewService
SearchService
UpdateQueue and IndexService
ReservationService
PaymentService, queue and processor
Hotel and room search
Hotel and room views
Reservation
ES indexing
Reservation
Payment
We use a relational DB because the need for strong consistency, and that data is managable by a single instance of DB.
We use ES for its query capabilities, especially keyword searches and geo-indexing.
SearchService, ViewService, ReservationService, PaymentService, PaymentProcessor and NotificationServices are stateless and can be scaled horizontally.
The database (on the order of 300GB) is managable by a single DB cluster. We enable high availability and replicas and hot standbys.
For the UpdateQueue and PaymentProcessor queue, the load also isn't high and we may not need sharding.
To handle peak load (e.g. 100X or normal traffic for reservations), our queuing system should smooth out the peak, but we can also implement backpressure on the client.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?