System Design · Design Question
Design a Booking System
Hotels / tickets / appointments: inventory, holds, payments, and how to avoid overselling under concurrency.
Concrete example: Two users booking the last deluxe room for the same night both pass search, but only one hold succeeds because the hold API decrements inventory inside a transaction or uses optimistic locking on the room-night row.
1. Requirements
Functional
- Search availability for a resource (room type / seat / slot) in a date range.
- Hold inventory briefly while user pays; confirm or release.
- No double booking of the same unique unit (or controlled overbook policy).
- Cancel/refund flows; idempotent booking APIs.
Non-functional
- Prevent accidental oversell under concurrency.
- Keep search fast while making hold/confirm strongly consistent and recoverable.
Back-of-envelope
2. API
3. Data model
For assigned seats/rooms, model each unit; for hotels often count-based inventory per room type per night.
4. High-level design
5. Concurrency: do not oversell
- Pessimistic:
FOR UPDATEon inventory rows — simple, correct. - Optimistic: version column; retry on conflict — good under low contention.
- Redis locks: possible for holds; still commit inventory in DB as source of truth.
6. Hold → pay → confirm saga
7. Search scaling
- Availability reads are heavy — cache popular hotel/date pages with short TTL.
- Accept brief stale “available” then fail at hold time (honest UX).
- Do not use cache as authority for the hold transaction.
8. Overbooking (optional product)
Airlines intentionally overbook statistically. If required, raise
total effective capacity and define compensation workflow —
say it explicitly; do not “accidentally” oversell.
9. Scaling writes
- Shard inventory by hotel_id.
- Hot hotel + hot dates → row contention; consider coarser locks or queue per hotel.
- Payment and notify async after confirm.
10. Edge cases
- Clock skew on hold expiry → use DB time.
- Partial multi-night failure → all-or-nothing nights in one TX.
- Double submit → Idempotency-Key on booking create.
11. Failure modes
- Payment succeeds but confirmation crashes → reconciler resumes by hold/payment ID.
- Expiry worker runs twice → conditional status update releases inventory once.
- Inventory DB unavailable → fail the hold safely; never confirm from cache.
Interview talking points
- Lead with: Separate cacheable search from the strongly consistent hold path.
- Separate search (cacheable) from hold/book (strongly consistent TX).
- Hold with TTL; worker releases expiry.
- Protect inventory with row locks or optimistic versions.
- Saga: hold → pay → confirm; compensate on failure.
- Idempotency keys on booking and payment.
- Shard by hotel; watch hot-date contention.
- Overbooking only as an explicit policy, not a race bug.