Design Ticketmaster
High-concurrency ticket reservation engine with temporary locking state control and ACID booking consistency.
1. System Requirements
- Search available events and venues.
- Display available seat charts in real-time.
- Hold selected seats for 10 minutes during checkout.
- Complete payment and book tickets (no double booking).
- Strong consistency for seat locks (absolutely no double booking).
- High concurrency tolerance during popular ticket sales.
- Graceful performance under high traffic spikes.
2. Scale & Resource Estimates
Throughput: Popular event releases can draw 100,000 concurrent users within seconds. Peak checkout load = 10,000 bookings/sec.
Storage & RAM: Primarily transaction logs and event data. Minimal storage footprint but highly write-sensitive.
3. System API Endpoints
// 1. Reserve seat block temporary lock
POST /api/v1/booking/lock
Request: { event_id: "evt-904", seat_ids: ["S-12", "S-13"], user_id: "usr-882" }
Response: { lock_id: "lck-1192", expires_at: 1783709472 }
// 2. Finalize payment booking
POST /api/v1/booking/confirm
Request: { lock_id: "lck-1192", payment_token: "tok-33948" }
Response: { ticket_id: "tkt-5512", status: "confirmed" }
4. Database Schema Design
Table: seat_status (PostgreSQL - ACID transactions)
- seat_id (VARCHAR - Primary Key)
- event_id (UUID - Foreign Key)
- status (ENUM: available, locked, sold)
- locked_by_user (UUID)
- lock_expiry (TIMESTAMP)
Table: bookings (PostgreSQL)
- booking_id (UUID - Primary Key)
- user_id (UUID)
- total_price (NUMERIC)
- status (ENUM: pending, paid, cancelled)
5. Interactive High-Level Architecture
6. Scalability Deep Dive & Bottlenecks
Enforces seat lock consistency. When a user selects a seat, a distributed lock is created in Redis with a 10-minute Time-To-Live (TTL). Inside PostgreSQL, transactions use pessimistic locking (`SELECT FOR UPDATE`) to verify the seat's status is 'available' before updating it to 'locked'. If payment fails or the TTL expires, the seat status is reset to 'available' automatically.
7. Production Scaling Strategies
Virtual Waiting Room: During flash sales (Taylor Swift, 50M+ requests), place users in a FIFO queue backed by Redis Sorted Sets (score = arrival timestamp). Release users to the booking flow at a controlled rate (e.g., 5K/sec) to prevent overwhelming the seat inventory DB.
Seat Inventory Partitioning: Partition seat inventory by event_id + section. Each section is an independent partition in PostgreSQL. Concurrent seat selections within different sections don't contend on the same rows. Use advisory locks per-section for fine-grained concurrency.
Rate Limiting + Bot Protection: Enforce per-IP and per-session rate limits (10 requests/sec) via Redis token bucket. CAPTCHA challenge on suspicious patterns. Device fingerprinting to detect automated scalper bots. Block requests from known datacenter IP ranges.
Payment Timeout Handling: Seat lock TTL = 10 minutes. If payment doesn't complete, Redis key expires and a background worker marks the seat as 'available' in PostgreSQL. Use Kafka dead-letter queue for failed payment events to ensure no seat is permanently locked.
Read Scaling for Seat Maps: Seat map renders are read-heavy (100:1 read:write ratio during sales). Cache seat availability in Redis with 1-second TTL. Serve seat map API from Redis replicas. Only write operations hit PostgreSQL primary.
Multi-Region Ticket Sales: For global events, run separate seat inventory per-region. Consolidate unsold inventory 24 hours before the event. Use distributed locking (RedLock) for cross-region seat transfers.
8. Runnable Production Starter Code
Scaffold