System Design 5: Design Hotel Booking App (Airbnb / Booking.com)
A hotel booking system is an open-ended, globally scaled distributed application that allows users to search for accommodations by location, name, and dates, check real-time availability, execute secure payments, and manage reservations. This comprehensive study note details the complete architecture, data models, microservices workflows, and concurrency control mechanisms required to build a production-grade system.
1. Problem Statement & Functional Requirements
In a system design interview, open-ended prompts like "Design Airbnb or Booking.com" require extracting precise functional and non-functional requirements. The system must support user onboarding, geospatial and textual search, detailed room availability checks, multi-step booking with payment processing, and reservation history tracking.
- User Authentication: Users must be able to sign up, log in, log out, and update their profile metadata.
- Hotel & Room Search: Users must be able to search for hotels based on location (geospatial proximity), name, and booking date ranges.
- Detailed Hotel & Availability View: Selecting a hotel must display rich metadata (amenities, descriptions, images) alongside available rooms and calculated pricing for the requested dates.
- Booking & Payment: Users must be able to reserve available rooms, execute secure payments, and receive confirmed booking reference IDs.
- Booking History: Users must be able to view all past and upcoming reservations in their profile.
2. Non-Functional Requirements & Scale Estimation
The system must scale to global traffic while handling critical consistency challenges around room inventory.
- Scale Targets: Designed for 50 million active users globally and 1 million hotel listings with extensive room inventories.
- CAP Theorem Trade-Offs:
- Availability (AP): Prioritized for the Search service. Users must be able to browse listings instantly, even if read replicas have slight replication lag.
- Consistency (CP): Prioritized for the Booking & Inventory service. Under no circumstances can two users successfully book the same room on the same date.
- Low Latency: Search queries must return p99 latencies under 200ms using caching and indexing layers.
3. Core Entities & API Design
Based on the functional requirements, the core entities of the system are Users, Hotels, Rooms, Pricing/Availability, Bookings, and Reviews.
REST API Endpoints
4. High-Level Architecture & Microservices Overview
Given the scale of 50 million users and 1 million hotels, a monolithic architecture will bottleneck. A decoupled Microservices Architecture evenly distributes traffic and isolates domain logic.
5. Low-Level Design: User & Review Services
User Service
- Responsibility: Onboards users and handles credential verification. Upon successful login, it issues a JWT (JSON Web Token) for subsequent authenticated requests.
- Database (
user_db): Relational MySQL/PostgreSQL database storing user metadata.
CREATE TABLE users (
user_id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
phone VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Review Service
- Responsibility: Handles user ratings, text reviews, and uploaded photos for specific hotels.
- Database & Storage: Metadata stored in MySQL; uploaded images stored in an AWS S3 bucket / Blob storage.
CREATE TABLE reviews (
review_id BIGINT AUTO_INCREMENT PRIMARY KEY,
hotel_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
rating INT CHECK (rating BETWEEN 1 AND 5),
comment TEXT,
image_url VARCHAR(512),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
6. Low-Level Design: Hotel Database & Storage Strategies
The hotel database manages highly relational data: hotels link to multiple rooms, and rooms link to dynamic price and availability records.
Database Schemas (PostgreSQL)
CREATE TABLE hotels (
hotel_id BIGINT PRIMARY KEY,
name VARCHAR(150) NOT NULL,
description TEXT,
address TEXT NOT NULL,
latitude DECIMAL(10, 8) NOT NULL,
longitude DECIMAL(11, 8) NOT NULL
);
CREATE TABLE rooms (
room_id BIGINT PRIMARY KEY,
hotel_id BIGINT REFERENCES hotels(hotel_id),
room_type VARCHAR(50) NOT NULL, -- e.g., Deluxe, Standard, Suite
capacity INT NOT NULL,
metadata JSONB
);
CREATE TABLE room_prices (
price_id BIGINT PRIMARY KEY,
hotel_id BIGINT REFERENCES hotels(hotel_id),
room_id BIGINT REFERENCES rooms(room_id),
price DECIMAL(10, 2) NOT NULL,
currency VARCHAR(3) DEFAULT 'USD',
start_date DATE NOT NULL,
end_date DATE NOT NULL
);
Room Availability Modeling: Two Approaches
Managing room availability across 1 million hotels and 300 rooms per hotel requires careful database design.
- Approach 1: Daily Record Per Room (Flat Calendar)
- Structure: Every room has 365 rows per year representing each day's status (
availableorbooked). - Pros: Extremely fast search queries without complex date-range calculations.
- Cons: Massive data volume ().
- Structure: Every room has 365 rows per year representing each day's status (
- Approach 2: Date Range Segments
- Structure: Stores availability as contiguous date intervals (e.g., Room A available from
Jan 1toMarch 31). - Pros: Significantly reduces row count.
- Cons: High write-complexity. When a user books a 3-day window, existing date ranges must be split, updated, and re-inserted safely.
- Structure: Stores availability as contiguous date intervals (e.g., Room A available from
7. Deep Dive: Search Service & Proximity Matching
Users search for hotels using textual titles and geographic locations. Querying relational tables with complex JOINs across millions of rows causes severe latency.
Why ElasticSearch?
While geospatial proximity can be solved using QuadTrees, PostgreSQL GIS extensions, or GeoHashes, none of these native spatial structures support full-text keyword searches out of the box.
- ElasticSearch provides native geospatial radius/distance queries (
geo_distance) alongside lightning-fast full-text search capabilities (leveraging internal GeoHash indexing).
Two-Phase Search Optimization
To prevent ElasticSearch from bloating with irrelevant room pricing and availability schedules:
- Phase 1 (ElasticSearch): The search service queries ElasticSearch using the hotel name, text, and
geo_distancefilters. ElasticSearch returns a lightweight list of matchinghotel_ids. - Phase 2 (Redis Cache / DB Filtering): Using the filtered
hotel_idlist, the search service executes a fast inner join against a Redis Cache containing room prices and availability for the requested date range, returning the final synthesized results to the client.
8. Deep Dive: Booking Service, Payments, and Concurrency Control
Booking a room is a multi-step transactional workflow involving payment verification, inventory locking, database persistence, and event notifications.
Event-Driven Architecture via Kafka
To prevent distributed deadlocks and tight coupling between the booking service, database updates, and notifications, the system uses an Apache Kafka Event Broker:
9. Concurrency Control: Preventing Double Booking
The most critical non-functional requirement is ensuring strict consistency—preventing two users from successfully booking the same room on the same date.
The Race Condition Scenario
- : User A searches and sees Room 101 is available.
- : User B searches and also sees Room 101 is available (because User A has not completed payment yet).
- : Both users submit booking requests simultaneously. Without concurrency controls, both payments might process, resulting in a double-booked room.
Two-Tier Defense Mechanism
- Availability Verification Check: Before redirecting a user to the payment gateway, the Booking Service queries the
Availability Serviceto re-verify room vacancy. If already booked, it rejects the request instantly. - Distributed Redis Locks with TTL:
- When a user initiates a booking, the system acquires a Redis Lock on that specific room for a short Time-To-Live (TTL, e.g., 5 minutes) to complete payment.
- If payment is not completed within 5 minutes, the Redis lock expires automatically, releasing the room back into the pool.
10. Summary and Key Takeaways
- Functional Scope: Designed end-to-end workflows for user onboarding, geospatial search, hotel details, reservations, payments, and history.
- Scale Requirements: Built to support 50 million users and 1 million hotel listings using a scalable microservices architecture.
- Database Selection: Utilizes MySQL/PostgreSQL for relational entities (Users, Bookings, Payments) and S3 blob storage for images and media.
- Search Optimization: Leverages ElasticSearch for combined textual and geospatial proximity matching, paired with a Redis cache for real-time room pricing.
- Event-Driven Reliability: Utilizes Apache Kafka to decouple booking confirmation, database persistence, and user notifications, preventing distributed blocking.
- Strict Consistency: Enforces strict CP guarantees on bookings using Distributed Redis Locks with TTL to eliminate double bookings during concurrent user checkouts.