Entity Range
Compute
Storage
Lets classify the CRUD flows
Search
GET /v1/hotels
Query params:
json response
{
hotels:[{id, name, location, rating, base price}]
pagination: {}
}
GET /v1/hotels/
response
{
id
name
description
amenenties
policies
review count
review_previews:[]
}
GET /v1/hotels/
query params:
response // give back the room tyes
{
rooms:[{id, type, amentities, price, available}]
}
<<<<< Reserve >>>>>
POST /v1/reservations
{
hotelId
roomId
checkIn
checkout
guest_info: {first, last, email,phone}
}
response
201
{
id
status
expiresat
}
Checkout
Idempotency-Key: 123
POST /v1/reservations/
{
payment_id:
}
response
201
{
success
}
Ok lets tackle the database design now. Since we are bounded by the number or reservations in the hotel catalog we aren't worried about unbounded rapid writes. And this seems like a read intensive application. I think that relational would be a good value here.
For example MySQL. WIth its B+ tree, all leaf nodes are on the same level and aid in range queries. Additionally WAL logging ensures durability and in addition to 2PC it ensures atomicity. In a cluster, it has async replication so we need to consider tradeoffs with a highly read heavy app. We can have a buffer on the frontend show n-1 available spots to account for inaccuracy.
Hard to guess hypothetically but we can user cockroachdb if we want strongly consistent reads and distributed nodes.
Since were working with relational lets talk about the db schema
User
Hotel # for data
Room # for data
Inventory
Booking
Reviews
Elasticsearch storage
Comments:
There is also an optimization component we can do with caching. Obviously we can cache the business and reservation data, but we can use the cache to interact and keep up to data for bookings. Since Redis can do atomic updates. Lets have the key hold inventory counts per day for a room that is queries. This is a write through cache where the redis counter is decremented and then the booking is sent async to a log based queue. The key can be
This will also help with high volume of writes in that the atonomicity of the counter as well with the high throughput of redis can handle, for exampe, 100k qps. To be atomic on both operations we can do a redis decrement, then a queue push. and if that fails rollback to an increment. If the queue push fails worst case we recover and be down 1 free room rather than be up a non-free room.
Lets talk about the request flows and how it interacts with the DB.
-> Searching based on location and dates
There is a whole other can of worms with the searching on the map. We can get to that later. Lets just say based on the search query we have a couple of hotel IDs. To hydrate the hotel information from the ids we can do a fetch from the hotel table in the db. It can contain things like CDN image, the name, rating.
query can be something like
SELECT h.* r.*
FROM hotel h
JOIN room r on
JOIN inventory i on
WHERE geohash LIKE 'dr5'%
WHERE inventory date between
WHERE inventory.available_count > 0
-> Searching for rooms on the specific hotel
Chances are that the user is going to click around hotels for dates around that time. So we can cache the previous query per date. For looking at room info, we can do something like
Select r.*
From room r
JOIN inventoy i on
WHERE inventory date between
WHERE inventory available_count > 0
-> Reserving
For the reservation flow we need to have the web app do a couple things. First it should decrement the redis room availability in the cache (if it exists). and in the same block add an entry to a booking log based event queue like kafka. This will 1) update the redis queue so that fetches for dates are accurate. This is helpful specifically on high traffic rooms so that visitors can get latest availability without pounding the database.
The event consumer can process the booking request async things it can do
Dynamic Pricing and Updates
Idempotency
Realtime updates
Search by name and category
Explain any trade offs you have made and why you made certain tech choices...
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?