Problem RestatementProblem
Design a scalable travel booking platform that lets tens of millions of daily users search, view, and book accommodations globally. The system must handle real-time inventory updates, per-date room rates, and maintain strong consistency for booking and payment flows while serving low-latency search results.
RequirementsRequirements
1.1 Functional
- Search Accommodations: By location, date, price, and various filters.
- Real-time Inventory: View up-to-the-minute availability and pricing.
- Booking & Payment: Securely book rooms with instant confirmation.
- Cancellations: Support user-initiated modifications and cancellations.
- Partner Portal: Allow hotels to manage and update inventory dynamically.
1.2 Non-Functional
- High Availability: Global reach with minimal downtime.
- Low Latency: Search results delivered in < 200ms.
- Strong Consistency: Critical for double-booking prevention and payments.
- Scalability: Handle millions of listings and multi-million concurrent users.
1.3 Scale Estimates
Listings
30 million properties
Daily Active Users
20 million
Booking Requests
100,000 per day
Search Queries
10,000 requests/sec
- Storage: Catalog data (TB), Inventory (In-memory), Archives (PB).
1.4 API Design
The core APIs required for the service:
/v1/searchSearchFiltered search for properties./v1/properties/:id/availabilityGet AvailabilityCheck specific room status./v1/bookingsCreate BookingInitiate a reservation./v1/partners/inventoryUpdate InventoryHotel partner update.High-Level ArchitectureArchitecture
2.1 Overview
- Search Service: Uses Elasticsearch for geo-spatial and text-based property discovery.
- Inventory Service: Manages real-time room availability using Redis for speed and SQL for durability.
- Booking Service: Orchestrates the transactional flow between inventory and payments.
2.2 Architecture Diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
U["User - Web/Mobile"] -->|"GET /search?location=Paris&dates=... "| AG["API Gateway"]
U -->|"POST /book {userId, hotelId, roomId, dates}"| AG
U -->|"GET /viewBooking {bookingId}"| AG
AG -->|"searchHotels(query)"| SS["Search Service"]
SS -->|"queryHotels(location, filters)"| CatalogDB[(Hotel Catalog DB)]
SS -->|"fetchRoomAvailability(hotelId)"| InvS["Inventory Service"]
HotelP["Hotel Partner System"] -->|"updateAvailability {hotelId, roomId, dates, count}"| InvS
InvS -->|"updateCache"| Redis[(Redis / In-Memory)]
InvS -->|"persistAvailability"| InvDB[(Inventory DB)]
InvS -->|"readAvailability"| Redis
InvS -->|"readAvailability"| InvDB
AG -->|"createBooking {hotelId, roomId, dates, userId}"| BS["Booking Service"]
BS -->|"atomicHold({roomId, dates})"| InvS
BS -->|"insertBookingRecord"| BookDB[(Booking DB)]
BS -->|"initiatePayment {bookingId, amount}"| PS["Payment Service"]
PS -->|"paymentCallback {bookingId, status}"| BS
BS -->|"updateBookingStatus"| BookDB
BS -->|"emitBookingEvent({bookingId, status})"| MQ[(Message Queue / Kafka)]
InvS -->|"emitInventoryUpdateEvent"| MQ
MQ --> NS["Notification Service"]
MQ --> Analytics[(Analytics / BI)]
NS -->|"notifyUser / hotel"| U
NS -->|"notifyHotelPartner"| HotelP
classDef userFlow fill:#f0f8ff,stroke:#333,stroke-width:1px;
classDef coreService fill:#e0ffe0,stroke:#333,stroke-width:1px;
classDef asyncFlow fill:#fff0f0,stroke:#333,stroke-width:1px;
classDef metaFlow fill:#fef7e0,stroke:#333,stroke-width:1px;
class U,AG userFlow;
class SS,InvS,BS,PS,Redis,CatalogDB,InvDB,BookDB coreService;
class MQ,NS,Analytics asyncFlow;
class HotelP metaFlow;🗃️ Data ModelData model
Listings Table
listings (
id UUID PRIMARY KEY,
name TEXT,
location GEOGRAPHY,
amenities JSONB,
rating FLOAT,
host_id UUID
)Room Types Table
A hotel sells several kinds of room (Standard, Deluxe, Suite), each with its own count and price, so availability is tracked per room type, not per listing.
room_types (
id UUID PRIMARY KEY,
listing_id UUID,
name TEXT,
capacity INT,
total_rooms INT
)Availability Table
availability (
room_type_id UUID,
date DATE,
available_rooms INT,
price DECIMAL, -- nightly rate for this date
version INT,
last_updated TIMESTAMP,
PRIMARY KEY (room_type_id, date)
)Bookings Table
bookings (
id UUID PRIMARY KEY,
user_id UUID,
listing_id UUID,
room_type_id UUID,
num_rooms INT,
check_in DATE,
check_out DATE, -- a booking reserves every night from check_in up to check_out
status ENUM('confirmed', 'cancelled', 'pending'),
payment_status ENUM('paid', 'refunded'),
created_at TIMESTAMP
)🔄 FlowsFlows
1. Search Flow
- User enters location, dates, filters
- Search API queries Catalog + Availability
- Results ranked by relevance, price, rating
- Cache top results for fast pagination
2. Booking Flow
- User selects listing and dates
- Booking Service checks availability
- Locks inventory and initiates payment
- On success: confirm booking and send notification
- On failure: release lock and notify user
3. Hotel Inventory Update
- Hotel updates availability via dashboard or API
- Event pushed to Kafka → Availability Service updates DB and Redis
- Search results refreshed if affected
4. Review Flow
- After checkout, user receives prompt
- Review stored and aggregated in Review Service
- Ratings updated in Catalog Service
📈 Scale ConsiderationsScale
- Use Elasticsearch for geo/text search
- Cache popular queries in Redis
- Partition availability data by region/date
- Use Redis or DB locks for booking consistency
- Deploy edge caches and regional data centers
- Use Kafka for async hotel updates and event propagation
🔍 Deep Dive TopicsDeep dive
1. Real-Time Availability Updates
Approach A: Pull-Based Sync
- Hotels update via dashboard; system polls periodically
Approach B: Push-Based Events
- Hotels push updates via API → Kafka → Availability Service
Approach C: Hybrid Model
- Pull for low-activity listings, push for high-volume partners
2. Booking Consistency
Approach A: DB Transactions
- Lock rows with SELECT ... FOR UPDATE
Approach B: Redis-Based Locking
- Use SETNX or Redlock
Approach C: Optimistic Locking with Versioning
- Compare version number during booking
Tradeoffs & ExtensionsTrade-offs
3.1 Tradeoffs
- Cache-Aside vs. Write-Through: Cache-aside is simpler and handles search spikes well, but a write-through cache for inventory ensures that users never see a "free" room that was just booked a second ago.
- Consistency vs. Availability: During a network partition, we prioritize consistency for bookings (stop accepting new ones if the DB is unreachable) but prioritize availability for search (allow users to browse cached property data).
3.2 Extensions
- AI Recommendations: Use past booking data to suggest personalized "similar properties" or "destinations you'll love".
- Dynamic Pricing (Surge): Implement an Uber-style surge pricing engine for peak seasons or high-demand events (e.g., Olympics, World Cup).
- Loyalty Program: Track "Nights Stayed" and automatically apply tiered discounts during the booking flow.
Wrap-UpWrap-up
Designing a platform like Booking.com requires solving the "Distributed Double-Booking" problem while maintaining lightning-fast search performance. By isolating the inventory lock from the broader metadata search, we create a system that is both technically robust and user-friendly at a global scale.