0 XP · 0 scenes

Design a ticket booking system

Design Interviews · lesson 15 of 15 · about 30 min

Design a ticket booking system

A ticket-booking system end to end: demand that can never be met, why a seat must be held while someone pays, how bots win a plain race, how to show a live seat map to a crowd, how a popular section overloads one partition, and what to do when a payment lands after the hold ran out. Tap any for a plain-language card.

0 / 9 sections done
  1. 1Forty per seat3 min
  2. 2Holding a seat5 min
  3. 3Bots and scalpers4 min
  4. 4The live seat map3 min
  5. 5Hot sections4 min
  6. 6Pick the mechanism2 min
  7. 7Who lives by this1 min
  8. 8Interview angle3 min
  9. 9Break It: the late payment4 min

Words in this lesson6Tap one for its meaning.

Demand the system can never satisfy

The stadium has 50,000 seats. Two million people open the page the moment sales start. 1,950,000 of them will be disappointed. How should they find out?

The sizing is unusual: the total volume is tiny (50,000 sales), but the contention is enormous. What matters is how many buyers can be in checkout at once, how long each takes, and how the crowd waiting is treated. Estimate the selling time and the odds.

2 million people for 50,000 seats is 40 buyers per seat, so only 2.5% can succeed. With 2,000 checkouts at once and 4 minutes each the sale takes about 100 minutes.

Buyers per seat40
Chance a given person gets a ticket2.5%
Time to sell out (seats ÷ concurrency × checkout time)100 min
People who will be told no1.95M

2.00 million people for 50,000 seats is 40 buyers per seat: 2.5% can succeed and 1.95M cannot. With 2,000 buyers in checkout at once and 240 s each, the sale lasts about 100 minutes.

Arithmetic. Admission control (a waiting room) is what keeps the crowd from overwhelming the checkout; see the lessons on e-commerce and rate limiting.

“Sorry, that seat was just taken” at the payment screen

You picked seat 14C, typed your card number, and pressed Pay. The page says someone else bought it a minute ago.

The hold turns a late, expensive failure into an early, cheap one, at the price of seats being locked while people dither (see the e-commerce lesson on Little's law). It also needs an atomic claim: “set held-by me if free or expired” as one conditional update. Compare how many people hit the late failure when 3,000 users chase 1,000 seats and the front rows are most wanted.

3,000 users and 1,000 seats with popularity skew 1.0 and 40 s to pay: the optimistic design makes 1,624 people fail at the payment step, about 1,080 person-minutes of wasted effort. With holds that is 0; refusals happen at selection instead.

  • Fail at the payment screen: check at payment
    1,624
  • Fail at the payment screen: hold at selection
    0
Seats sold917 of 1,000 (92%)
Failures after entering payment details1,624
Effort wasted on those1,083 person-min
Seat clicks refused immediately7,547

Checking only at payment, 1,624 people reached the pay button for a seat already gone: about 1,083 person-minutes wasted. 917 seats sold.

Seeded event simulation: arrivals uniform over two minutes, seats chosen by Zipf desirability, up to four attempts per person, 2 s to try another seat, holds last 120 s.

The first thirty seconds belong to scripts

Half the traffic on sale day is bots, and each one clicks twenty times faster than a human can. Who gets the tickets?

Defences are layered because none is perfect. Remove the speed advantage: a waiting room that assigns random places instead of rewarding the fastest request. Limit what one identity can do: verified accounts (phone or payment-linked), a per-account ticket cap, and per-card and per-address limits. Add bot detection (behavioural signals, device checks, ), and make the supply of accounts costly. Compare the free-for-all with a cap.

50% of requesters are bots, 20 times as fast: in a free-for-all they take 95% of the seats. If each account may buy 4 tickets and the bot operator has verified 1,000 accounts, they can hold at most 4,000 of 50,000 seats, 8%.

  • Bots' share: free-for-all
    95% (47.6K seats)
  • Bots' share: verified accounts with a cap
    8% (4K seats)
Bots' share without limits95%
Most seats the bots can hold with the cap4K
Bots' share with the cap8%

With 50% bots each 20× as fast, a free-for-all gives them 95% of the seats. A cap of 4 tickets per verified account, against an operator with 1,000 accounts, limits them to 4K seats, 8% of the total.

Share model: bots' share ≈ f·s ÷ (f·s + 1 − f), then limited by (accounts × cap) ÷ seats. Real bot operators also rent accounts and use residential IPs, so identity cost is the lever.

Every grey seat should turn grey as it sells

One hundred thousand people are staring at the seat map. Every sale changes one seat. Does each change go to each viewer?

Cheaper designs decouple the two numbers. Serve the seat map as a cached snapshot (from a CDN or an in-memory store) refreshed every half second to a second, and let clients poll it or receive one batched update per interval, so cost is viewers ÷ interval whatever the sale rate. Send only the section the person is looking at, send deltas rather than the full map, and treat the map as advisory: the authoritative check happens when a seat is claimed, so a slightly stale map costs a refused click, never a double sale.

200 changes a second and 100,000 viewers: broadcasting each change is 20 million messages a second. A snapshot every 500 ms is 200,000 a second, 100 times fewer.

  • Push every change to every viewer
    20M/s
  • Batched snapshot
    200K/s
Messages per second: per-change push20M
Messages per second: batched200K
Reduction100×
Longest a viewer can see a stale seat500 ms

200 changes a second shown to 100K viewers is 20M messages a second if each change is pushed to each viewer, but 200K with a 500 ms snapshot: 100× fewer, with a seat map at most 500 ms out of date.

Arithmetic: per-change push = changes × viewers per second; batched = viewers × (1000 ÷ interval ms). The claim step stays authoritative.

Everyone wants the floor

Thousands of claims a second, but they are not spread evenly: the front sections are chosen far more than the back. Which database partition takes the heat?

Remedies: partition finer in the hot area (by row or by seat block rather than whole section); split a hot section's inventory into independent sub-pools that are claimed separately; keep the hottest counters in memory with an atomic operation and flush to the database; and use best available allocation (“give me any 2 together in this price tier”) which spreads demand over many seats instead of fixing it on named ones. Try the skew.

20 sections, 5,000 claims a second and partitions that can each commit 500 a second: with Zipf skew 1.0 the busiest section is asked for about 1,390 claims a second, so only 3,915 of 5,000 (78%) are served. With no skew all 5,000 are.

  • Offered
    5K
  • Busiest section is asked for
    1.39K/s (limit 500)
  • Served
    3.92K
Claims served per second3.92K
Rejected or delayed22%

With 20 sections, skew 1.0 and 500 claims a second per partition, the busiest section is asked for 1.39K a second. The system serves 3.92K of 5K claims (22% lost to the hot partition).

Arithmetic: served = Σ min(section demand, partition capacity), with section demand proportional to 1 ÷ rank^skew.

Pick the mechanism

Six problems, four mechanisms.

Each problem has one mechanism that fits best. Each answer is worth 20 XP.

Match the symptom: failing at the pay button, bots, update flood, or a saturated hot partition?

Question 1 / 6

Customers reach the payment screen and then learn the seat was sold to someone else.

Tip: press 1 to 4 to answer, Enter for the next one.

Who lives by this

Selling the scarce.

Public facts about ticketing and flash demand.

A stress test in publicTicketmaster, 2022 presale

extreme demand

Ticketmaster publicly reported that a major 2022 presale drew several billion system requests, several times its previous peak, with far more fans than seats, a case study in demand exceeding any capacity you can provision.

Fixing identityVerified Fan programmes

registration before the sale

Ticketing companies introduced registration-based access, where fans sign up in advance and a subset is selected and sent codes, to take speed and anonymity out of the contest and to make bots more expensive to run.

Making bots illegalBOTS Act (US, 2016)

law against circumvention

The Better Online Ticket Sales Act made it illegal in the United States to use software to circumvent a ticket seller's purchase limits or security measures, an acknowledgement that the problem needs legal as well as technical defences.

A daily flash crowdTatkal booking on Indian Railways

fixed-time quota opening

IRCTC opens its Tatkal quota at fixed times each day, and the rush of simultaneous bookings at those moments is a long-running example of predictable flash demand on a numbered-inventory system.

Interview angle

What interviewers actually ask.

Six questions, each worth 20 XP. Strong answers cover fairness, holds, bots and the late-payment edge case.

Say how a seat is protected, how the crowd is admitted and how abuse is limited.

Question 1 / 6

What makes ticketing different from ordinary e-commerce?

Tip: press 1 to 3 to answer, Enter for the next one.

Break it

Your card is approved at 5 minutes and 3 seconds. The seat hold ended at 5 minutes. In those three seconds someone else was given the seat.

The rules that prevent this: when a payment starts, move the seat into a “payment in progress” state that expiry does not release; set the hold a little longer than the realistic payment time (and show a countdown); on confirmation do an atomic check that the seat is still reserved for this order; if it is not, refund automatically and offer alternatives. The seat is released only when the payment fails, is cancelled, or times out with the processor.

With a 5-minute hold and a median 2-minute payment, 6.2% of payments land after the hold expires; at 50,000 payments and 30% of those seats re-sold, about 925 customers would be charged for a seat someone else has. A 10-minute hold cuts late payments to 0.3%.

Payments completing after the hold expires6.2%
Number of them3,083
Customers charged for a seat that was re-sold925

6.2% of 50,000 payments (3,083) finish after a 5.0-minute hold; 30% of those seats were re-sold, so 925 customers are charged for a seat someone else owns and must be refunded.

Payment time is log-normal (sigma 0.6) around the median; late = payments slower than the hold. Re-sale share is an input, not a measurement.

Where to go next