Hotel Reservation System (Airbnb / Booking.com)
Problem statement
Design a hotel booking platform: search rooms by location and dates, reserve a room type for a date range, pay, manage cancellations — with inventory tracked per room type per night.
Requirements
Functional
Search hotels by location, dates, guests; show availability and price.
Reserve a room type for a date range; confirm after payment.
Cancel/modify with policy-based refunds.
Hotel admins manage rooms, rates, inventory.
Optional controlled overbooking (e.g. 10%).
Non-functional
Reservations strongly consistent: never below zero inventory beyond the overbooking allowance.
Search p99 < 500 ms; reads scale independently.
5M hotels, 100M room-nights of inventory in a 2-year window.
Multi-currency pricing.
Back-of-the-envelope estimates
- Inventory rows: 5M hotels × 3 room types × 730 days ≈ 11B rows (hotel_id, room_type, date, total, reserved) → partition by hotel_id; ~50 B/row → 550 GB.
- Reservations: 1M/day ≈ 12/s; writes tiny.
- Search: 100M/day ≈ 1.2k/s; each search touches up to 30 nights × N hotels → precomputed availability caches per (city, date).
API
GET /v1/hotels/search?city=&checkin=&checkout=&guests= → hotels with min price & availability
GET /v1/hotels/{id}/rooms?checkin=&checkout=
POST /v1/reservations { hotelId, roomTypeId, checkin, checkout, guests, idempotencyKey } → { reservationId, status }
POST /v1/reservations/{id}/pay
DELETE /v1/reservations/{id}
PUT /v1/admin/hotels/{id}/inventory { roomTypeId, date, total }
Data model
hotels (hotel_id, name, geo, address, ...)
room_types (room_type_id, hotel_id, name, capacity)
rates (room_type_id, date, price, currency)
room_inventory(hotel_id, room_type_id, date, total_rooms, reserved_rooms, version) PK(hotel_id, room_type_id, date)
reservations (reservation_id, user_id, hotel_id, room_type_id, checkin, checkout, status, amount, idempotency_key UNIQUE)
Inventory is per room type per night, not per physical room — assignment to a physical room happens at check-in.
High-level design
- Search service: Elasticsearch for hotel attributes + geo; availability from a date-range availability cache (per hotel/room type: bitmap of available nights) so search filters on availability without hitting the inventory DB. Cache updated on every reservation change.
- Reservation service: in one transaction, for each night in
[checkin, checkout):UPDATE room_inventory SET reserved_rooms = reserved_rooms + 1 WHERE … AND reserved_rooms + 1 <= total_rooms * (1 + overbook_pct). If any night fails → rollback → 409. Then insert the reservation aspending_paymentwith a TTL. - Payment via the payment service; success →
confirmed; timeout → release inventory. - Rates: per-date pricing table; total computed at reservation time and stored (price lock).
- Sharding: inventory and reservations sharded by
hotel_idso a reservation's nights are in one shard → single-shard transaction. - Hotel admin writes inventory/rates; changes publish events for the availability cache.
Architecture diagram
Deep dives
Per-night inventory is the key modelling decision: it makes overlapping stays trivial (each night is an independent counter) and search fast (bitmaps), at the cost of many rows — fine when partitioned.
Overbooking: total × (1 + pct) in the predicate; ops dashboards show hotels over 100%.
Long stays: a 30-night reservation updates 30 rows in one transaction — acceptable; cap stay length.
Rate/price consistency: store the computed price on the reservation; rate changes never affect existing bookings.
Bottlenecks & mitigations
Popular hotel on popular dates → contention on a few inventory rows; keep transactions short, retry with jitter.
Search fan-out over availability → bitmaps in cache; precompute per (city, month).
Availability cache invalidation lag → search may show a room that just sold; reservation returns 409 and search refreshes.
Failure modes
- Payment fails/times out: reservation TTL expiry releases the nights.
- Availability cache stale: worst case a 409 at reservation — never an overbooking.
- Shard down: only that hotel set is unbookable; search degrades to 'availability unknown'.
- Double reservation on retry: idempotency key unique constraint.
Follow-up questions interviewers ask
How would you implement dynamic pricing?
How would you handle a hotel that sells inventory on multiple platforms (channel manager)?
How would you model physical room assignment and upgrades?