Ticketmaster sells 500+ million tickets per year with extreme traffic spikes: a popular concert on-sale can attract millions of users in seconds. Designing a ticketing platform tests your understanding of high-concurrency inventory management, virtual waiting rooms, seat locking, and dynamic pricing — all under the constraint that overselling is catastrophic (selling a seat to two people). This guide covers the architecture for handling flash-sale scale.
Seat Inventory and Double-Booking Prevention
Each event has a venue with sections, rows, and seats. Each seat has a state: AVAILABLE, HELD (temporarily reserved while a user is in checkout), SOLD, or BLOCKED (held by the venue). The core invariant: a seat must never be sold to two people. Prevention: (1) Optimistic locking — UPDATE seats SET status = HELD, held_by = user_id WHERE seat_id = X AND status = AVAILABLE. If 0 rows updated, the seat was already claimed. Retry with a different seat. (2) Redis atomic claim — SET seat:{seat_id} {user_id} EX 480 NX. The NX flag (set only if not exists) ensures only one user claims the seat. TTL 480 seconds (8 minutes) auto-releases if checkout is abandoned. (3) Database unique constraint — a UNIQUE constraint on (event_id, seat_id) in the orders table prevents duplicate sales at the database level. Even if the application logic has a bug, the database rejects the second sale. Layer all three: Redis for fast atomic claims at the application layer, PostgreSQL unique constraint as the safety net, and optimistic locking for state transitions. The 8-minute hold: when a user selects seats, they are held for 8 minutes to complete checkout. If they do not complete payment, the hold expires and the seats return to AVAILABLE. A background job checks for expired holds every 30 seconds.
Virtual Waiting Room
A Taylor Swift on-sale attracts 14+ million users. Without a queue, the system would crash under the load. The virtual waiting room meters demand to match system capacity. Architecture: (1) Users arrive at the event page before the on-sale time. They receive a queue token (UUID) and are placed in a Redis sorted set: ZADD queue:{event_id} {arrival_timestamp} {token}. (2) The queue page shows position (ZRANK) and estimated wait time via SSE or WebSocket. (3) A scheduler job runs every 30 seconds: admits the next N users based on system capacity. ZPOPMIN queue:{event_id} N returns the N earliest tokens. (4) Admitted users receive a signed JWT (admission token) with an expiry. This token grants access to the seat selection page. The token is verified at every checkout step. (5) The admission rate N is calibrated based on: remaining ticket inventory (do not admit more than remaining tickets), checkout capacity (how many concurrent checkouts the payment system can handle), and historical conversion rates (not everyone who is admitted buys). Fairness: users are admitted strictly in arrival order (FIFO). Ticketmaster also uses Verified Fan: pre-registered fans are given priority queue positions based on engagement history (purchased tickets before, follows the artist). Bots are blocked via CAPTCHA, device fingerprinting, and IP rate limiting at the queue entry point.
Flash Sale Architecture
The on-sale moment creates a traffic spike 100-1000x normal. Architecture layers: (1) CDN for static content — the event page, images, venue map, and JavaScript are served from CDN cache. Zero backend load for page renders. (2) Virtual queue — absorbs the user surge. Only N users per batch reach the backend. (3) Seat availability cache — seat availability is cached in Redis. The seat map UI reads from Redis, not the database. Redis handles 300K+ reads/sec on a single instance. (4) Horizontal auto-scaling — application servers auto-scale based on queue depth and CPU. Pre-scale 30 minutes before the on-sale based on anticipated demand (estimated from queue size). (5) Database connection pooling — PgBouncer pools connections to prevent exhausting PostgreSQL max_connections during the spike. (6) Read replica offloading — seat availability queries hit read replicas. Write operations (seat holds, purchases) go to the primary. (7) Circuit breakers — if the payment gateway is slow, the circuit breaker fails fast. Users see “try again in a moment” rather than a 60-second timeout. The entire infrastructure is pre-warmed before the on-sale: DNS propagation, CDN cache, auto-scaled servers, and warmed database connection pools.
Seat Selection UX
Interactive seat map: the venue layout is rendered as an SVG or Canvas element. Each seat is clickable with real-time availability coloring (green = available, gray = held/sold, blue = selected by you). Real-time updates: as other users claim seats, the map updates in real-time via WebSocket or SSE. A seat that was available 2 seconds ago may now be held by someone else. The client receives seat_status_changed events and updates the visual. This creates urgency (“seats are going fast”) and prevents frustration (clicking a seat that is already taken). Best available: for users who do not want to pick specific seats, the “best available” algorithm selects the best N seats based on: section priority (center > sides), row priority (closer to stage for concerts, center rows for theater), consecutive seats (a group of 4 should sit together), and aisle preference (end seats for accessibility). The algorithm searches available seats section by section, finding consecutive blocks of the requested size, scoring each by quality, and returning the top option. For general admission (standing, no assigned seats): no seat map. The inventory is a simple counter. Decrement atomically on purchase. When counter reaches 0, the event is sold out.
Dynamic Pricing
Dynamic pricing adjusts ticket prices based on demand, similar to airline pricing. Factors: (1) Demand signals — queue depth (how many users are waiting), purchase velocity (tickets sold per minute), and historical demand for similar events. (2) Supply — remaining inventory per section. As premium sections sell out, prices for remaining sections may increase. (3) Time to event — prices typically increase as the event date approaches (urgency premium). Last-minute drops may occur if inventory remains. (4) Comparable events — prices of similar events in the same market. Implementation: a pricing engine runs continuously during the sale. It reads demand metrics (from Redis counters) and adjusts prices per section every 1-5 minutes. Updated prices are stored in Redis and reflected in the checkout flow. Price locking: when a user selects seats, the price is locked for the duration of their hold (8 minutes). They pay the locked price even if prices increase. This prevents frustration from price changes during checkout. Transparency: display the price clearly before the user commits. Some jurisdictions require showing all fees upfront (not just the base price). Ticketmaster shows: base price + service fee + facility fee = total. Resale marketplace: for sold-out events, Ticketmaster operates a verified resale marketplace where ticket holders can list tickets at market prices. The original barcode is transferred and the old one is invalidated.
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How does Ticketmaster prevent double-booking of seats?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Three layers: (1) Redis atomic claim: SET seat:{id} {user_id} EX 480 NX. The NX flag ensures only one user succeeds. TTL 480 seconds (8 minutes) auto-releases if checkout is abandoned. (2) Optimistic locking: UPDATE seats SET status=HELD WHERE seat_id=X AND status=AVAILABLE. Zero rows updated means another user claimed it. (3) Database unique constraint on (event_id, seat_id) in the orders table rejects duplicate sales even if application logic has bugs. All three layers work together: Redis handles the high-concurrency fast path, optimistic locking manages state transitions, and the unique constraint is the ultimate safety net. The 8-minute hold gives users time to complete checkout. A background job checks for expired holds every 30 seconds and releases them.”}},{“@type”:”Question”,”name”:”How does a virtual waiting room handle millions of users for a flash sale?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Users arriving before the on-sale are placed in a Redis sorted set: ZADD queue:{event_id} {timestamp} {token}. The queue page shows position (ZRANK) and estimated wait via SSE/WebSocket. Every 30 seconds, the scheduler admits N users: ZPOPMIN returns the N earliest tokens. Admitted users receive a signed JWT granting access to seat selection. Admission rate N is calibrated by: remaining inventory (do not admit more than remaining tickets), checkout system capacity (concurrent payment processing limit), and historical conversion rates. Fairness: strict FIFO by arrival time. Bots blocked via CAPTCHA, device fingerprinting, and IP rate limiting at queue entry. Ticketmaster Verified Fan gives pre-registered fans priority positions based on engagement history.”}}]}