Skip to content

Ticketmaster / BookMyShow#

Problem statement (interviewer prompt)

Design Ticketmaster / BookMyShow: users browse events, see a seat map, hold a seat for ~7 minutes while paying, then receive a ticket. Guarantee no double-booking even during 500k-concurrent-user drops for hot shows. Add anti-bot defences.

flowchart LR
  U([User])
  CAT[Event Catalog]
  SEAT[Seat Map Service]
  HOLD[Seat Hold<br/>TTL lock]
  PAY[Payment]
  TKT[Ticket Issue]
  U --> CAT
  U --> SEAT
  SEAT --> HOLD
  HOLD --> PAY --> TKT

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class U client;
    class CAT,SEAT,HOLD,PAY,TKT service;
flowchart TB
  subgraph Clients
    WEB
    MOB
  end

  subgraph Edge
    CDN
    LB
    WAF[WAF + Bot filter]
    QUEUE[[Virtual Queue / Waiting Room]]
  end

  subgraph Discover
    EVT[Events Catalog]
    SRCH[Search]
    EVDB[(Events DB)]
  end

  subgraph Seat[Seat selection]
    MAP[Seat Map renderer]
    SEATSVC[Seat Service]
    SEATDB[(Seats per show<br/>strong consistency)]
    HOLD[Hold Service<br/>TTL 7-10 min]
    LOCK[Redis SETNX EX lock per seat]
  end

  subgraph Buy
    CKT[Checkout]
    PAYSVC[Payment]
    PG((Payment Provider))
    IDEM[Idempotency keys]
    SAGA([Booking saga])
  end

  subgraph Issue
    TKT[Ticket Issuer]
    QR[QR / barcode]
    EMAIL[Email / SMS]
    WALLET[Apple/Google Wallet]
  end

  subgraph Anti[Anti-abuse]
    CAPTCHA
    BOT[Bot scoring]
    LIMIT([Per-user limits])
    BLACKLIST
  end

  subgraph After
    REFUND[Refund / cancel]
    RESALE[Resale / Transfer]
    SCAN([Venue scanner])
  end

  Clients --> CDN --> LB --> WAF --> QUEUE --> Discover
  Discover --> Seat --> HOLD --> LOCK
  HOLD --> Buy --> Issue
  Anti --- Clients
  After --- Issue

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class LIMIT client;
    class WAF edge;
    class EVT,SRCH,MAP,SEATSVC,HOLD,CKT,PAYSVC,IDEM,TKT,QR,EMAIL,WALLET,BOT,REFUND,RESALE service;
    class EVDB,SEATDB datastore;
    class LOCK cache;
    class QUEUE queue;
    class SAGA,SCAN compute;
    class PG external;

Seat reservation correctness#

  • Each seat is a unique row in seats(show_id, seat_id, state) with state machine: available → held → sold.
  • Hold = atomic CAS update to held with held_until = now + TTL.
  • Background sweeper releases expired holds.
  • Selling = CAS held → sold only if owner_id matches and payment captured.

Waiting room#

  • High-demand events route users to a virtual queue (Cloudflare-style).
  • Random fair-share lottery; users enter the buy flow in waves.
  • Prevents thundering herd on seat APIs.

Anti-bot#

  • Heavy captcha + behavioral fingerprinting.
  • Per-account / per-IP / per-payment-method limits.
  • Account age and history matter for hot drops.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD CDN edge caching for static assets cdn
HLD CAP / PACELC C vs A under partition; L vs C otherwise cap-pacelc
HLD Distributed transactions 2PC, TCC, sagas, outbox/inbox distributed-transactions
HLD Idempotency & retries safe re-execution, backoff + jitter idempotency-retries
HLD Search internals inverted index, BM25, embeddings, ANN search-internals
LLD State machines FSM, HSM, transitions, guards state-machines
LLD REST API design verbs, statuses, pagination, errors rest-api-design
LLD Behavioural patterns Strategy, Observer, State, Command, Chain behavioral-patterns
LLD Concurrency primitives mutex, semaphore, RW lock, atomic, CAS concurrency-primitives

Quick reference#

Functional#

  • Browse events, view seat map, hold, pay, get ticket.
  • Wait-list, refund, resale.
  • Anti-bot, fair queueing for hot drops.

Non-functional#

  • Strict no-double-booking.
  • Survive flash crowds (10-100× normal traffic) for marquee events.
  • p99 hold response < 1 s under load.

Capacity#

  • Big drop: 500k+ concurrent users in queue.
  • Seat catalog: 100k+ seats for a stadium.

Schema#

  • events(id, venue_id, time, status)
  • shows(id, event_id, hall, sale_start)
  • seats(show_id, seat_id, state, held_by, held_until, version)
  • bookings(id, user_id, show_id, seat_ids[], payment_id, status, idempotency_key)

Trade-offs#

  • Strong consistency on seats non-negotiable; pay the latency.
  • TTL holds prevent permanent leaks but require sweepers.
  • Virtual queue is mandatory for big drops or service melts down.
  • Resale complicates ticket identity → unique IDs, key rotation per transfer.

Refs#

  • Ticketmaster engineering "Verified Fan" posts.
  • BookMyShow architecture talks.
  • ByteByteGo "Design ticketing", Alex Xu Vol 2.

FAQ#

How does Ticketmaster prevent two users from buying the same seat?#

Each seat has a row in a strongly consistent store. A short TTL hold is taken at click time using compare and set, and the hold is converted to a sold state only after payment succeeds.

How does Ticketmaster handle 500k concurrent users for a hot drop?#

A waiting room throttles entry, randomizing or queueing users into the checkout funnel. Pre-warmed caches absorb reads while the seat hold service runs on dedicated capacity.

What happens if a user's payment fails during seat hold?#

The seat hold expires automatically via a TTL or an explicit release on payment failure. The seat returns to the pool and another user can claim it via the same hold then pay flow.

How does Ticketmaster fight bot ticket scalpers?#

Defenses include captcha, device fingerprinting, behavioral signals, rate limits per account and IP, and verified fan programs. Suspected bot traffic is shadow banned or sent to slow queues.

How is the seat map rendered for large venues?#

The seat map is precomputed as static SVG or vector tiles by section. Real time availability is overlaid via a separate websocket or polled JSON channel keyed by section.

Video walkthrough

System Design Interview: Design Ticketmaster : via Hello Interview