Event Ticketing System Low-Level Design

Requirements

  • Users can browse events, select seats from a seat map, reserve seats, and complete payment
  • Prevent double-booking: no two users can book the same seat for the same event
  • Handle demand spikes: popular events (Taylor Swift, Super Bowl) have tens of thousands of simultaneous buyers
  • Seat holds expire after 10 minutes if payment is not completed

Data Model

Event(event_id, venue_id, name, date, status ENUM(ONSALE,SOLDOUT,CANCELLED))
Venue(venue_id, name, total_capacity, seat_map_json)
Seat(seat_id, venue_id, section, row, number, category ENUM(GA,FLOOR,BALCONY))
SeatInventory(seat_id, event_id, status ENUM(AVAILABLE,HELD,SOLD), held_by, held_until)
Order(order_id, user_id, event_id, status ENUM(PENDING,CONFIRMED,EXPIRED,CANCELLED),
      created_at, expires_at, total_amount)
OrderItem(item_id, order_id, seat_id, price)

Seat Reservation Flow

  1. User selects seats on the seat map
  2. POST /orders/hold: BEGIN TRANSACTION; SELECT * FROM SeatInventory WHERE seat_id IN (…) AND event_id=X FOR UPDATE; verify all are AVAILABLE; UPDATE SeatInventory SET status=’HELD’, held_by=user_id, held_until=NOW()+10min; create Order (PENDING, expires_at=+10min); COMMIT
  3. User completes payment within 10 minutes
  4. POST /orders/{id}/confirm: BEGIN TRANSACTION; verify Order status=PENDING and not expired; charge payment; UPDATE SeatInventory SET status=’SOLD’; UPDATE Order SET status=’CONFIRMED’; COMMIT

The SELECT FOR UPDATE serializes concurrent seat selections. If two users try to hold the same seat, one gets the lock and succeeds; the other finds status=’HELD’ and fails with SeatUnavailable error.

Hold Expiry

A background job runs every 30 seconds: SELECT * FROM SeatInventory WHERE status=’HELD’ AND held_until < NOW(). For each expired hold: UPDATE SeatInventory SET status=’AVAILABLE’, held_by=NULL, held_until=NULL WHERE status=’HELD’ AND seat_id=X (compare-and-swap to avoid racing with a concurrent payment confirmation). UPDATE Order SET status=’EXPIRED’. Notify the next user in the queue (if waitlist exists).

High-Demand Sale Architecture

  • Virtual queue: before sale opens, users join a queue. At sale time, release users in batches (e.g., 1000 every 30 seconds). Each released user gets a signed purchase token (JWT) valid for 10 minutes. Only token holders can enter the purchase flow.
  • Rate limiting: max 1 queue entry per user per event. Redis SET nx per user+event.
  • CDN: event listing page and seat map SVG served from CDN — no origin hit until seat selection
  • Read replicas: seat availability queries go to read replica; writes go to primary
  • Seat map cache: cache seat availability bitmap in Redis (bitset per event, bit per seat), updated on each reservation. Display uses cached bitmap; actual booking uses DB.

Seat Map Availability at Scale

Fetching all 50,000 seats’ status per page load from DB would be too slow. Use a Redis bitset: key=availability:{event_id}, one bit per seat_id. Bit=1 means available. SETBIT on reserve, GETBIT on display. The bitmap for a 50,000-seat venue is only 6KB. Cache with TTL=5s; slight staleness is acceptable for display (actual booking still validates in DB). Serve the bitmap to clients; render the seat map in JavaScript.

APIs

GET  /events/{id}/seats          → seat availability bitmap
POST /orders/hold                → {event_id, seat_ids[]} → Order
POST /orders/{id}/confirm        → {payment_token} → Order (CONFIRMED)
DELETE /orders/{id}              → cancel hold, release seats
GET  /orders/{id}                → Order status

Key Design Decisions

  • SELECT FOR UPDATE on SeatInventory rows prevents double-booking without application-level locking
  • 10-minute hold + expiry job ensures inventory is not held hostage by abandoned sessions
  • Virtual queue absorbs the spike; DB sees metered traffic, not a stampede
  • Redis bitset for display, DB for authoritative booking

Airbnb system design covers reservation and availability systems. See common questions for Airbnb interview: reservation and booking system design.

Stripe system design interviews cover payment flows and atomic reservations. See patterns for Stripe interview: payment and seat reservation system design.

Amazon system design covers high-demand reservation systems. Review design patterns for Amazon interview: ticketing and reservation system design.

Scroll to Top