System Design Problems
Design a Ticket Booking System
A ticket booking system allows users to browse events, select seats, and purchase tickets. Systems like Ticketmaster handle millions of concurrent users during high-demand onsales (e.g., Taylor Swift tickets) without double-booking seats.
- Inventory Management β Real-time seat availability with no double-booking
- High Concurrency β Handle 10M+ users competing for limited seats
- Payment Processing β Atomic reservation and payment with timeout release
The core challenge is preventing double-booking under extreme concurrency while keeping the user experience fast and responsive.
Requirements
Functional Requirements
- Users can browse events and view available seats
- Users can select seats and hold them temporarily (5-minute window)
- Users can complete purchase with payment
- Seats are released if payment not completed within hold window
- Support for different seat categories and pricing
- Users can view their booking history
Non-Functional Requirements
- Consistency: No double-booking under any concurrency level
- Availability: 99.99% uptime during onsale events
- Latency: Seat selection response < 200ms
- Scalability: Handle 1M concurrent users for a single event
Ticket booking is a classic inventory management problem. The critical invariant is: a seat can be in only one of three states: available, held, or booked. The hold state has a TTL that automatically releases the seat.
Back-of-the-Envelope Estimation
Booking System Capacity
- 1000 events/day, 50,000 seats each = 50M seats/day
- Peak onsale: 1M concurrent users for one event
- QPS_read: 1M / 10 (page refreshes) = 100K QPS
- QPS_write: 1000 bookings/sec (seat selection)
- Payment processing: 500 transactions/sec
- Storage: 50M bookings Γ 500 bytes = 25 GB/day
High-Level Architecture
Detailed Design
Seat Reservation Flow
The seat reservation is the critical path. Use optimistic locking or distributed locks to prevent double-booking:
DfOptimistic Locking
Optimistic locking assumes conflicts are rare. Read the current version, attempt to update with a version check (WHERE version = expected_version), and retry if the version has changed.
Seat State Machine
DfSeat States
Seats transition through three states: available β held (with TTL) β booked (after payment). If payment is not completed within the hold window, the seat returns to available.
Hold TTL Mechanism
Use Redis with TTL for automatic seat release:
Seat Hold with TTL
Here,
- =Redis key for the seat hold
- =User who holds the seat
- =Hold duration in seconds (typically 5 minutes)
Use Redis keyspace notifications to detect expired holds. When a hold expires, a listener receives a key expiration event and updates the database to mark the seat as available.
Database Schema
CREATE TABLE seats (
id BIGINT PRIMARY KEY,
event_id BIGINT NOT NULL,
section VARCHAR(20),
row VARCHAR(5),
number INT,
status VARCHAR(10) CHECK (status IN ('available', 'held', 'booked')),
held_by BIGINT,
held_until TIMESTAMP,
version INT DEFAULT 0,
price DECIMAL(10, 2)
);
CREATE INDEX idx_event_seats ON seats(event_id, status);
CREATE UNIQUE INDEX idx_seat_unique ON seats(event_id, section, row, number);
Handling Flash Sales
For high-demand events with millions of concurrent users:
Use a virtual waiting room (queue) to rate-limit users entering the booking flow. This prevents database overload and provides a fairζι experience.
- Users enter a virtual queue when onsale starts
- Queue processes 1000 users at a time
- Each user gets a 5-minute booking window
- If not booked, user re-enters the queue
Queue Processing Rate
Here,
- =Total seats available
- =Expected booking completion rate
- =Hold window duration in seconds
Practice Exercises
-
Concurrency: If two users try to book the same seat simultaneously, design the exact sequence of database operations to prevent double-booking.
-
Scale: For an event with 50,000 seats and 1M concurrent users, estimate the Redis memory needed for seat holds and the database write throughput.
-
Reliability: What happens if the payment service goes down while users have held seats? Design a recovery mechanism that doesn't lose money or double-book.
-
Optimization: How would you implement a seat selection UI that shows real-time availability to millions of users without overwhelming the backend?
Key Takeaways:
- Optimistic locking with version checks prevents double-booking without distributed locks
- Redis TTL-based holds provide automatic seat release without background jobs
- The seat state machine (available β held β booked) ensures clean transitions
- Virtual waiting rooms protect the backend during flash sales
- Keyspace notifications enable real-time hold expiration processing
What to Learn Next
-> Design Payment System Payment processing, idempotency, and financial transactions.
-> Data Replication Strong consistency and leader election for booking databases.
-> Distributed Consensus Raft and Paxos for distributed coordination.
-> Caching Strategies Redis caching patterns for seat inventory.
-> Message Queues Async payment processing and order confirmation.
-> Load Balancing Handling flash sale traffic spikes with load shedding.