All questions
#18Commerce & PaymentsHard

Design Ticketmaster (Event Booking)

Sell a fixed set of seats to a crowd without ever double-booking.

Amazon logo
Microsoft logo
Airbnb logo
Stripe logo

Asked at Amazon, Microsoft and 2 more

3 min readยท8 sections

Ticketmaster sells a fixed number of seats for each event. Most of the time traffic is calm, then a popular concert goes on sale and millions of people try to buy the same 50,000 seats in the same minute. The design must never sell a seat twice, stay fair, and survive that spike.

Requirements#

Functional

  • Browse events and see seat maps with live availability.
  • Choose seats, hold them for a few minutes, then pay.
  • Receive a ticket once payment succeeds.

Non-functional

  • No double booking, ever. This is the one hard correctness rule.
  • Handle sale spikes of millions of concurrent users for a single event.
  • Seat maps can be a few seconds stale; the final booking cannot.

Booking flow#

  1. The user selects seats.
  2. The system reserves them for 10 minutes so nobody else can take them.
  3. The user pays.
  4. On success, the reservation becomes a confirmed booking. If the timer runs out, the seats are released.

Data model#

sql
seats (
  event_id     BIGINT,
  seat_id      VARCHAR(10),
  status       VARCHAR(10),   -- available | held | booked
  hold_id      UUID,
  held_until   TIMESTAMP,
  PRIMARY KEY (event_id, seat_id)
);

Reserving seats safely#

Two people clicking the same seat at the same moment must not both get it. A conditional update makes the reservation atomic:

sql
UPDATE seats
SET status = 'held', hold_id = :hold, held_until = now() + interval '10 minutes'
WHERE event_id = :event AND seat_id IN (:seats)
  AND (status = 'available' OR (status = 'held' AND held_until < now()));
-- Succeeds only if every requested seat was updated; otherwise roll back

This is optimistic: no locks are held while the user browses, and the database row is the single source of truth. A Redis lock per seat with a TTL is a faster alternative for the hold, as long as the final booking is still checked in the database.

Architecture#

Fans
CDNstatic event pages
Virtual waiting roomqueue + tokens
Virtual waiting room
Booking service
Seats DBstrongly consistent
Booking service
Payment service
Booking service
Seat map cacherefreshed every few s
Booking service
Booking events
Ticket + email workers
A waiting room meters traffic into the booking service; seat state lives in one strongly consistent store

Surviving the on-sale spike#

  • Virtual waiting room: instead of letting everyone hit the booking service, users join a queue and are let in at a rate the system can handle, each with a signed token. It's fairer too: a random position or first-come order instead of whoever retries fastest.
  • Static content at the edge: event pages, images and seat map layouts come from the CDN.
  • Cached availability: the seat map shows availability from a cache refreshed every second or two. Being slightly stale is fine because the reservation query is the real check.
  • Per-event isolation: a mega on-sale event can get dedicated capacity so other events keep working.

Payments and timeouts#

Payment providers can be slow. The hold timer gives the user time to pay; the booking service calls the payment service with an idempotency key tied to the hold, so retries never charge twice. If payment fails or the hold expires, the seats go back to available.

Bots and fairness#

Bots buy tickets to resell them. Countermeasures include the waiting room, per-account and per-card purchase limits, CAPTCHA at entry, and verified fan programs that issue access codes ahead of the sale.

Finished this walkthrough?

Mark it as read to track your progress in the list.