Ticket Booking
Concurrency control on hot seats. Hybrid Redis+DB holds, virtual queue for drops, anti-scalping.
The scenario
Concurrency on hot seats — where virtual queues, Redis holds, and Ticketmaster's 3.5B-request crash converge
Same startup, same engineer #4. Sixteenth Monday.
Your CTO drops by. "We want to build a ticket booking system. Concerts, sports, theater. Assigned seating. Users pick specific seats on a map, hold them for 10 minutes to complete purchase. Ship an MVP in 12 weeks."
She pauses. "For context — on November 15, 2022, Ticketmaster handled 3.5 BILLION requests trying to sell Taylor Swift Eras Tour tickets. 3.5 million fans pre-registered. Bots amplified the load 4x beyond their previous peak. The site crashed within minutes. Congressional hearings + DOJ antitrust suit followed. This is the archetypal high-concurrency inventory problem — and getting it wrong is a career-defining event. If you don't design for hot-seat concurrency + bot mitigation + virtual queues from Day 1, you're building a Taylor Swift crash."
Here's the paradigm shift:
Ecommerce was bipolar (99% browse, 1% checkout). But even during BFCM/Prime Day, checkout is distributed across MILLIONS of products — no single item gets 100% of load.
Ticket booking is monopolar concurrency: for a Taylor Swift concert, EVERY buyer wants EXACTLY ONE of a fixed set of seats — say, 20,000 seats for a stadium show. If 2 million people show up in 30 seconds, that's 100:1 demand-to-supply. Every buyer targets the same DB rows. Pessimistic locks would deadlock immediately. Optimistic locks retry-storm the system. This is the hardest concurrency problem in system design because the answer is NOT database primitives — it's an architecture that FLATTENS demand before it touches the database:
- Virtual queue at CDN edge — Cloudflare Waiting Room / Fastly Traffic Peak (or built-in). Users see a queue page BEFORE their request touches your servers. Fair, throttled admission at the rate your DB can handle.
- Redis-based seat holds — writes go to Redis (100K+ writes/sec/node), NOT the source-of-truth DB. Seat becomes "held" for 10 minutes; if purchase completes, the hold becomes permanent in DB. Otherwise it releases.
- Bot mitigation at edge — 70%+ of Taylor Swift's 3.5B requests were bots. Cloudflare Turnstile + rate limiting + fingerprinting + presale invitation tokens are table stakes.
- Anti-scalping enforcement — max 4 tickets per user, verified identity, resale price caps by state law.
Ticketmaster's answer was inadequate: their virtual queue + Verified Fan system was designed for ~1M concurrent registrants, but Taylor Swift attracted 3.5M pre-registered users PLUS bots amplifying to billions of requests. The DOJ suit alleges monopoly (they control 70% of primary ticketing + venue exclusives), but the technical failure was real. Reference: Educative's system-design analysis of the meltdown.
The real 2024 numbers
- Ticketmaster Nov 2022 Taylor Swift Eras Tour: 3.5 BILLION system requests in one day (4x their previous peak) — Variety coverage
- 3.5M pre-registered fans, 1.5M invited to buy, 2M on waitlist
- 2M+ tickets sold in one day (single-artist-tour record)
- Ticketmaster processes ~500M tickets/year globally across all events
- StubHub Q4 2024: ~40M active buyers, ~$8-10B GMV (StubHub S-1 2024 IPO filing)
- DICE / Eventbrite / Live Nation all operate at similar scales for their event portfolios
- Bot traffic: 70-80% of ticket-sale requests are bots in unmitigated systems
Interview soundbite: "Ticket booking is monopolar concurrency — 2 million buyers targeting 20K seats in 30 seconds. Pessimistic locks deadlock. Optimistic locks retry-storm. The answer is architecture that FLATTENS demand: (1) virtual queue at CDN edge before requests hit servers, (2) Redis seat holds with 10-min TTL because DB writes can't scale to millions/sec, (3) bot mitigation at edge because 70%+ of demand is bots, (4) anti-scalping enforcement. Ticketmaster's 2022 Taylor Swift crash was 3.5B requests in one day = 4x their previous peak. If you don't mention virtual queues + Redis holds + bot mitigation, you'll fail L5."
The whole journey at a glance
Every 10× in buyers-per-second surfaces different bottlenecks — starting with the DB:
text═══════════ TICKET BOOKING ACROSS 4 SCALES ═══════════ L4 (100 buyers) L5 (10K buyers) L6 (100K buyers) L7 (Taylor Swift 2M in 30s) Django + PG Redis holds + queue Multi-region + bot mit Virtual queues everywhere 12 weeks · $500/mo 6 months · $50K/mo 18 months · $500K/mo ongoing · $10M+/yr ┌────────┐ ┌────────┐ ┌── Global CDN ─────┐ ┌── Multi-CDN + Turnstile ┐ │ Web │ │ Web │ │ Cloudflare + │ │ Cloudflare + Akamai │ │Mobile │ │Mobile │ │ Turnstile (bots) │ │ + custom bot detection │ └───┬────┘ └───┬────┘ └─┬──┬──┬──┬─────────┘ └──┬──┬──┬──┬───────────┘ │ │ │ │ │ │ │ │ │ │ ┌──▼───┐ ┌──▼──┐ ┌──▼──▼──▼──▼─────┐ ┌───▼──▼──▼──▼───────────┐ │ ALB │ │ ALB │ │ Virtual queue │ │Virtual queue (edge) │ │ │ │+ WAF│ │ (Cloudflare │ │+ Verified Fan tokens │ └──┬───┘ └──┬──┘ │ Waiting Room) │ │+ presale invitation │ │ │ └───┬──────┬─────┘ │+ cryptographic proof │ │ │ │ │ └──┬──┬──┬──┬────────────┘ ┌──▼──────┐ ┌───▼─────────┐ ┌───▼──────▼───┐ │ │ │ │ │ Django │ │ Java Spring │ │ API tier │ ┌──▼──▼──▼──▼───────────┐ │ + PG │ │ + MySQL │ │ + rate │ │Multi-region API tier │ │ Simple │ │ + Redis │ │ limiter │ │+ per-tenant rate │ │ holds │ │ seat holds │ │+ bot filter │ │+ sticky-session queue │ │ in PG │ │ 10min TTL │ └───┬──────┬───┘ │+ cross-region routing │ └──┬──────┘ │ + Kafka │ ┌───▼──────▼──┐ └──┬──┬──┬──┬────────────┘ │ └───┬─────────┘ │Seat holds │ │ │ │ │ │ ┌───▼──┐ │ in Redis │ ┌──▼──▼──▼──▼───────────┐ │ │Redis │ │ Cluster │ │Redis Cluster │ │ │seat │ │ 100K writes │ │seat holds · sharded │ │ │holds │ │/sec/node │ │by event_id · 100K WPS │ │ │10min │ │+ SETNX for │ │+ Lua scripts for │ │ │TTL │ │ atomic hold│ │ atomic operations │ │ └───┬──┘ └───┬──────────┘ └──┬─────────────────────┘ ┌──▼───┐ ┌───▼─┐ ┌───▼──────────┐ │ │Postgr│ │MySQL│ │Sharded MySQL │ ┌──▼──────────────────────┐ │(events │+ 2 │ │+ Vitess │ │Vitess sharded MySQL │ │+ seats │repl │ │+ optimistic │ │+ optimistic locks + │ │+ orders │icas │ │ locks │ │ event-scoped isolation │ │+ users) │ │ │+ Stripe pay │ │+ Stripe/Adyen failover │ │Multi-│ │ │ └───┬──────────┘ │+ chargeback recon │ │AZ) │ └─────┘ │ └──┬───────────────────────┘ └──────┘ ┌───▼──────────┐ │ │Kafka events │ ┌──▼──────────────────────┐ │+ analytics │ │Kafka event fanout │ │+ email conf │ │+ real-time analytics │ └──────────────┘ │+ email/SMS notification │ └──────────────────────────┘ Bottleneck Bottleneck Bottleneck Bottleneck Simple direct Hot seat contention Bot traffic 70%+ Ticketmaster reality: Postgres holds. in Postgres kills overwhelms edge. 3.5B requests/day at Works up to throughput. Need Need virtual queue Taylor Swift Eras Tour 100 buyers. Redis holds. + Turnstile. scale = 4x prev peak. Chapter 5 Chapters 6+6.5 Chapter 7+7.5 Chapter 8 walks walks through walks through virtual walks through Ticketmaster through Redis SETNX holds queue + Turnstile bot 2022 postmortem, virtual L4 MVP + Kafka events mitigation queue architecture, and anti-scalping enforcement Key insight: Ticket booking is MONOPOLAR concurrency. 2M buyers, 20K seats, 30s window. Databases can't handle direct writes at this ratio. The answer is architecture that FLATTENS demand BEFORE the database: virtual queue at edge + Redis holds + bot mitigation + anti-scalping. Ticketmaster's 3.5B-request crash in Nov 2022 = the case study for what happens when you don't plan for this. If you name virtual queues + Redis holds + Turnstile + Verified Fan tokens you're L6+.
The same 4 tiers as clean architecture diagrams
L4 · 100 buyers · Django + Postgres · $500/mo · 12 weeks:
flowchart TD
W([Web / Mobile]) -->|HTTPS| LB[ALB]
LB --> API[Django API<br/>c5.large]
API --> PG[(Postgres Multi-AZ<br/>events + seats + holds<br/>+ orders)]
API --> ST[Stripe API<br/>checkout]
classDef n fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
class LB,API,PG,ST nL5 · 10K buyers · Redis holds + Kafka · $50K/mo · 6 months:
flowchart TD
W([Web / Mobile]) -->|HTTPS| LB[ALB + WAF<br/>rate limit]
LB --> API[Java Spring Boot<br/>+ Kafka producer]
API --> RD[(Redis Cluster<br/>seat holds<br/>SETNX + 10min TTL)]
API --> DB[(Sharded MySQL<br/>events + orders)]
API --> KF[Kafka event fanout<br/>analytics · email · SMS]
API --> ST[Stripe API]
classDef n fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef m fill:#fef3c7,stroke:#d97706,color:#78350f
class LB,API n
class RD,DB,KF,ST mL6 · 100K buyers · Virtual queue + bot mitigation · $500K/mo · 18 months:
flowchart TD
W([Global users]) -->|HTTPS| CDN[Cloudflare<br/>+ Turnstile bot check<br/>+ Waiting Room queue]
CDN --> LB[Regional ALB<br/>+ rate limiter]
LB --> API[100+ microservices<br/>+ per-region routing]
API --> RD[(Redis Cluster<br/>seat holds<br/>sharded by event_id<br/>Lua scripts for atomicity)]
API --> DB[(Vitess sharded MySQL<br/>+ optimistic locks)]
API --> KF[Kafka events<br/>analytics · notification]
API --> ST[Stripe → Adyen failover]
classDef n fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef m fill:#fef3c7,stroke:#d97706,color:#78350f
classDef s fill:#dcfce7,stroke:#16a34a,color:#14532d
class CDN,LB,API n
class RD,DB,ST,KF mL7 · Taylor Swift 2M in 30s · Multi-CDN + Verified Fan · $10M+/yr:
flowchart TD
W([Global users<br/>+ bots]) -->|HTTPS| CDN[Multi-CDN<br/>Cloudflare + Akamai<br/>+ custom bot detection]
CDN --> VQ[Virtual queue<br/>+ Verified Fan tokens<br/>+ presale invitation<br/>+ cryptographic proof]
VQ --> LB[Multi-region ALB<br/>+ sticky sessions]
LB --> API[100+ microservices]
API --> RD[(Redis Cluster sharded<br/>seat holds by event_id<br/>Lua atomic ops)]
API --> DB[(Vitess MySQL<br/>+ optimistic locks<br/>+ event-scoped isolation)]
API --> AS[Anti-scalping svc<br/>4-ticket limit<br/>+ identity verify]
API --> KF[Kafka event fanout<br/>real-time analytics<br/>+ email/SMS]
API --> ST[Stripe/Adyen<br/>failover + chargeback recon]
classDef n fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef m fill:#fef3c7,stroke:#d97706,color:#78350f
classDef s fill:#dcfce7,stroke:#16a34a,color:#14532d
class CDN,LB,API n
class RD,DB,KF,ST m
class VQ,AS sWhy every 10× breaks the architecture
- Redis seat holds are the L5 signal. Direct DB writes for seat holds cap at ~10K writes/sec (fsync bound). Redis Cluster does 100K+ writes/sec/node. Use SETNX (SET if not exists) for atomic hold acquisition; 10-minute TTL auto-releases abandoned holds. Reference: Redis SETNX docs.
- Virtual queue at CDN edge is the L6 signal. Cloudflare Waiting Room (or Fastly's equivalent) queues users BEFORE their request reaches your servers. Admits N users per minute at the rate your DB can handle. Fair, throttled, no bot advantage. Reference: Cloudflare Waiting Room.
- Bot mitigation is the L6+ non-negotiable. 70%+ of Taylor Swift's 3.5B requests were bots. Cloudflare Turnstile + fingerprinting + presale invitation tokens with cryptographic proof are table stakes. Reference: Cloudflare Turnstile + Verified Fan presale mechanics.
The 3 senior insights before we start Chapter 1
- Ticket booking is monopolar concurrency. Every candidate says "we use Redis for caching." L6+ candidates explain that Redis is not a cache here — it's the source of truth for holds during the sale window, then holds are promoted to the DB on purchase completion. Naming this signals L6 preparation.
- Virtual queue is the architectural primitive. Cloudflare Waiting Room queues users BEFORE the request reaches your API. Do NOT try to build a queue at your API tier — you'll get the Ticketmaster crash. Naming Cloudflare Waiting Room or Fastly Traffic Peak signals awareness of production reality.
- Bot traffic is 70-80% of demand. Cloudflare Turnstile + presale invitation tokens + Verified Fan cryptographic proofs are table stakes. Congressional hearings after the Taylor Swift 2022 crash focused specifically on bot mitigation failures.
Chapter map for the journey ahead
- Chapter 1 — Requirements (event, seat, hold, purchase, cancellation, resale)
- Chapter 2 — Capacity estimation (Taylor Swift 3.5B request reference, 2M buyers in 30s)
- Chapter 3 — API design (browse, hold, purchase, cancel, waitlist)
- Chapter 4 — Data model (events, venues, seats, holds, orders — with state machines)
- Chapter 4.5 — Seat-hold algorithm: Redis SETNX + Lua scripts for atomic holds
- Chapter 5 — L4 MVP: Django + Postgres. Works to 100 buyers
- Chapter 6 — L5: Redis holds + Kafka event fanout + Stripe
- Chapter 6.5 — Virtual queue architecture: Cloudflare Waiting Room deep-dive
- Chapter 7 — L6: Multi-region + bot mitigation + Vitess sharding
- Chapter 7.5 — Bot mitigation deep-dive: Turnstile + Verified Fan tokens
- Chapter 8 — L7: Taylor Swift 2022 postmortem + anti-scalping enforcement
- Chapter 9 — Failure modes: hold lock leak, bot storm, payment provider outage, oversell
- Chapter 10 — Trade-off matrix (Ticketmaster vs StubHub vs DICE vs Eventbrite)
- Chapter 11 — Interview masterclass: 45-min mock, questions to ask
- Chapter 12 — Defense: the 20 hardest interview questions on ticket booking
Ready? Chapter 1 next: what did the CTO actually ask for?
Ticket booking is monopolar concurrency: 2M buyers targeting 20K seats in 30 seconds. Pessimistic locks deadlock. Optimistic locks retry-storm. The answer is architecture that FLATTENS demand BEFORE the database: (1) virtual queue at CDN edge (Cloudflare Waiting Room), (2) Redis seat holds with SETNX + 10-min TTL, (3) bot mitigation at edge (70%+ of Taylor Swift's 3.5B requests were bots), (4) anti-scalping enforcement. Ticketmaster's Nov 2022 Taylor Swift Eras Tour crash was 3.5B requests in one day = 4x their previous peak. Naming virtual queues + Redis holds + Turnstile + Verified Fan tokens signals L6+ preparation.
- Why is ticket booking monopolar concurrency and how does it differ from ecommerce?
- What is the Taylor Swift 2022 crash and what caused it?
- How does Redis SETNX + 10-min TTL solve the seat-hold problem?
- Why is a virtual queue at CDN edge (Cloudflare Waiting Room) the L6 primitive?
- How does Cloudflare Turnstile + Verified Fan tokens mitigate 70% bot traffic?
Every concept below has its own interactive, animated page in the Learning Tracks section. Read them any time you want to go deeper than the mentor prose above — they're the reusable foundation this chapter is built on.
The algorithm behind Redis Cluster shard placement for seat holds — events are sharded by event_id so hot events land on isolated shards.
Post-purchase side effects (email confirmation, SMS, analytics, fulfillment) all flow through Kafka to keep checkout latency low + avoid coupling.
Chapter 1 next: what did the CTO actually ask for? Event, seat, hold, purchase, cancellation, resale — each has functional and non-functional requirements. Get these wrong and you'll design the wrong system.
Components used in this design
Study each component's deep dive to understand it in isolation.
Load Balancer
Distributes incoming traffic across a pool of servers for scale and fault tolerance.
Redis
An in-memory key-value store used for caching, pub/sub, rate limiting, distributed locks, and simple queues.
SQL Database
A row-oriented, ACID-compliant relational database — the default for transactional workloads.
Distributed Lock (ZooKeeper, etcd, Redis Redlock)
Cross-node mutual exclusion — 'only one node can do this at a time' when you can't rely on a single-node lock.
Rate Limiter
Enforces per-caller (per-user, per-IP, per-tenant) request budgets to protect downstream systems from abuse and overload.
Patterns applied in this design
Study each pattern's deep dive for the recurring solution logic.
Saga (Long-running distributed transaction)
You have a business transaction that spans multiple services or databases (place order → charge payment → reserve inventory → send confirmation). Two-phase commit is too slow, too coupling, and often not available across service boundaries.
Rate limiting
One bad actor can consume all your capacity. And even good actors need bounds so you can capacity-plan.
Explore next — related systems
If you enjoyed this problem, these share similar patterns or challenges.