System Design Visualized
System design interview · Hard · about 45 minutes

Design a ticket booking system

Design a ticket booking system like Ticketmaster. Users browse events, pick seats on a seat map, hold them for a few minutes while they pay, and get their tickets. Popular concerts sell out in minutes.

contentionconsistencywaiting room
Practise it in the interview simulatorDraw your design on a canvas, stress test it with real traffic, and get a scored report. Or watch this answer build itself, step by step.

1. Clarify the requirements

Before drawing anything, ask questions. These are the answers an interviewer would typically give:

How many users?
100 million users a month; about 1 million tickets are sold on a normal day.
What about hot events?
A big stadium tour: 10 million people try to buy 50,000 seats in the first 10 minutes of the sale.
Assigned seats?
Yes: users pick specific seats on a seat map. Some events are general admission.
How long is a hold?
Seats are held for 10 minutes while the user pays, then released if they don't finish.
Payments?
Through an external payment provider. Never charge twice and never sell a seat twice.
How fresh must availability be?
The seat map may be a few seconds out of date while browsing, but booking must be strictly correct.

2. Estimate the scale

Assumptions: 1M tickets sold per normal day. A hot on-sale: 10M people arrive in the first 10 minutes for 50,000 seats, and each refreshes the seat map about 10 times.

  • Normal booking rate: about 11.6 bookings/s1M ÷ 86,400 ≈ 12 bookings/s. Average load is tiny; the spikes are the problem.
  • People arriving per second at the on-sale: about 17K users/s10M ÷ 600 s ≈ 17K new people per second.
  • Seat-map reads per second at the on-sale: about 167K reads/s10M × 10 refreshes ÷ 600 s ≈ 170K reads/s.
  • People competing for each seat: about 200 people/seat10M ÷ 50,000 = 200 people per seat.

3. The high-level design

FansCDNEvent pagesWaiting roomLoad balancerBooking serviceSeats & ordersPostgreSQLSeat map cachePayment jobsPayment workersPayment providerMetrics & alerts
The reference design. Dashed arrows are asynchronous.
  1. Event pages from a CDNEvent pages and the seat map image are static: served from a CDN, so the on-sale rush doesn't hit your servers for them.
  2. A waiting roomWhen 10 million fans arrive at once, a virtual waiting room (a queue plus a rate limiter) lets them in at the pace the booking service can handle, and blocks bots.
  3. Seats in a transactional databaseA seat can be sold once: hold it with a conditional update the database applies atomically. Availability is cached and refreshed every few seconds.
  4. Payments off the critical pathPayment happens after the hold, through a queue and workers; if it fails or the hold expires, the seat is released.
  5. Watch it in productionMetrics and alerts close the loop: waiting-room length, hold expiry rate and double-booking checks.

4. The components and what each one does

CDN CDN
Event pages and static assets from the edge.
Waiting room Rate limiter
Virtual queue + rate limiter: admits fans at a safe rate; blocks bots.
Load balancer Load balancer
Spreads requests over the stateless servers behind it, health-checks them and routes around a dead one. Rate limits abusive clients.
Booking service App servers
Holds a seat for 10 minutes with an atomic conditional update (no double booking), then takes payment.
Seats & orders SQL database · PostgreSQL
UPDATE seats SET held_by=… WHERE id=… AND status='free': atomic, so no double booking. Sharded by event; primary + replicas with failover.
Seat map cache Cache
Seat availability, refreshed every few seconds.
Payment workers Workers
Charge with an idempotency key; release the seat on failure or timeout.
Payment provider 3rd-party service
Card payments.
Metrics & alerts Metrics & alerts
Dashboards and alerts on p99 latency, error rate, queue depth and cache hit ratio, so a bottleneck shows up before it becomes an outage.

5. Deep dive: no double booking under contention

Thousands of people click the same seat at the same moment. How do you make sure each seat is sold exactly once, hold seats while people pay, and keep the system alive when 10 million people arrive at once?

  • A hold is a reservation with an expiry, taken with a conditional write that only succeeds if the seat is still available.
  • Optimistic concurrency: UPDATE seats SET status='held', hold_id=… WHERE id=? AND status='available'. Exactly one request changes the row.
  • A virtual waiting room admits people at the rate the booking system can handle; everyone else sees their place in line.

6. What interviewers listen for

  • Hold and booking APIsPOST /events/{id}/holds {seatIds} returns a holdId and expiry; POST /bookings {holdId, payment, idempotencyKey} confirms.
  • Data model: events, seats, holds, bookingsSeat rows with a status (available, held, sold) and a version make conflicts detectable.
  • Atomic hold: conditional update or row lockExactly one of many simultaneous requests may win a seat; a conditional write (or a row lock) guarantees it.
  • Holds expire and seats are releasedIf a buyer abandons checkout, the seat must come back automatically.
  • Virtual waiting room for on-sales10 million people can't all reach the inventory at once; admit them at the rate it can handle and show a fair place in line.
  • Idempotent payment and bookingRetries and double clicks happen. An idempotency key makes sure each purchase is charged and booked once.
  • Hold → pay → confirm, with compensationIf payment succeeds but confirming fails (or the reverse), you need a defined way to undo.
  • Browsing may be stale; booking is strictA cached, slightly stale read path plus a strongly consistent write path is what makes the system both fast and correct.
  • Bot and scalper protectionHot on-sales attract bots; captchas and per-account limits keep tickets for real fans.
  • Database replication and failoverA single database is a single point of failure. Replicas give redundancy and read capacity; failover promotes a replica when the primary dies.
  • Partition (shard) data as it growsOne machine eventually can't hold the data or the write load. Say how you'd split it and by which key.

7. Follow-up questions

  1. Two people press 'Book' on seat A12 in the same millisecond. Walk me through what your design does.
  2. A buyer holds four seats, then closes the browser. What happens to those seats?
  3. Sales for a stadium tour open at 10:00 and 10 million people are waiting. What does each of them see, and what protects your database?
  4. The payment provider times out. Did the customer pay? What does your system do next?
Answer them in the simulator

The key points for each follow-up, your scored report and the stress test are part of Pro: ₹299 a month or ₹1,999 a year.

See Pro

The design in a nutshell

  • Clients → CDN (event pages, cached seat maps) → load balancer → stateless API servers.
  • On-sales go through a virtual waiting room that admits people at a fixed rate and shows their place in line.
  • Hold: a conditional update in a transactional database (UPDATE seat SET status='held', hold_expires=now()+10min WHERE id=? AND status='available'); expired holds are released by a background job.
  • Book: charge through a payment provider with an idempotency key, then mark the seats sold in one transaction; refund or release if a step fails.
  • The inventory database is the source of truth; seat maps are cached and slightly stale; per-account limits and bot checks.

Related lessons: Transactions and isolation · Idempotency keys · What a rate limiter does, and why

Now design it yourself

Reading an answer isn't the same as giving one. Draw ticket booking system on the canvas, defend your numbers, survive a 10× traffic spike, and see exactly what an interviewer would flag.

Open the interview simulator