System Design Interview: Design Ticketmaster w/ a Ex-Meta Staff Engineer
Tony Duong
Jun 5, 2026 γ» 6 min

Notes from Hello Interview (ex-Meta staff engineer) on designing a Ticketmaster-like ticket booking service β a top question at Meta (product design and system design interviews).
Interview roadmap
- Requirements (functional + non-functional)
- Core entities + APIs
- High-level design (satisfy functional requirements)
- Deep dives (satisfy non-functional requirements)
Keep requirements under ~5 minutes.
Functional requirements
- Users can search for events
- Users can view an event (details, seat map, available tickets)
- Users can book tickets
Non-functional requirements (context-specific)
Don't just list "scalability" and "availability" β explain what makes this system hard.
| Concern | Ticketmaster-specific framing |
|---|---|
| Consistency vs availability (CAP) | Strong consistency for booking β no double booking (one seat, one user). High availability for search/view β OK if a new event appears a few seconds late |
| Read/write ratio | ~100:1 (many browse, few buy; ~1% conversion) |
| Scaling | Not generic scale β surges from popular events (Taylor Swift, Super Bowl, World Cup) |
| Low-latency search | Full table scan won't work |
Out of scope (note below the line): GDPR, generic fault tolerance details, etc. β check priorities with interviewer.
Core entities
- Event (venue, performer, metadata, relation to tickets)
- Venue (location, seat map)
- Performer
- Ticket (seat, price, status, event FK)
Start with entity names; detail fields as design evolves.
APIs
View event
GET /events/{eventId} β event, venue, performer, list of tickets (for seat map)
Search
GET /search?term=&location=&type=&date=... β list of partial events (enough for results; full detail via view endpoint)
Book (two-phase β like real Ticketmaster)
- Reserve:
POST /booking/reserveβ body:ticketIdonly; user from JWT/header, not body (security) - Confirm:
PUT/PATCH /booking/confirmβticketId+ payment details β Stripe (webhook callback on success)
Reserve holds the seat ~10 minutes while user pays.
High-level architecture
Client β API Gateway (auth, rate limiting, routing) β microservices:
| Service | Role |
|---|---|
| Event CRUD | View event, load seat map data |
| Search | Event discovery |
| Booking | Reserve + confirm |
PostgreSQL for primary storage β relationships (event β tickets), ACID transactions for booking correctness. SQL vs NoSQL is a weak debate in interviews; focus on required qualities (transactions, consistency on tickets). Either Postgres or DynamoDB with transactions could work.
Ticket status: available | reserved | booked (+ user ID when booked)
Stripe for payments (async; webhook confirms success before marking booked).
Reservation expiry β the key design decision
Problem: User reserves, abandons payment β seat stuck reserved forever.
Mid-level: timestamp + query or cron
- Add
reserved_timestamp; query treatsreservedolder than 10 min as available - Or cron every ~10 min to reset stale reservations
Downside (senior gap): cron introduces delay n β seat may stay locked up to cron interval past 10 minutes (e.g. 19 minutes total).
Senior: Redis distributed lock with TTL
- On reserve: don't update Postgres status β set
ticketIdin Redis with TTL = 10 minutes - On seat map: query
availabletickets, then filter out IDs present in Redis lock - TTL expires β seat automatically available (no cron lag)
- Separate Redis because multiple booking service instances need one consistent lock view
If Redis fails: brief window where double-book attempts possible; Postgres ACID still ensures one winner on confirm β bad UX for losers, acceptable trade-off to discuss with product.
Deep dives
Low-latency search β Elasticsearch + CDC
Initial design: SQL LIKE wildcard β full table scan β too slow.
Elasticsearch with inverted index for text search; geospatial support for location.
Don't use ES as primary store (durability, transactions). Sync from Postgres:
- Dual-write in app code (handle partial failure), or
- CDC β stream β update ES (common interview answer; events/venues rarely change β no queue needed)
Caching popular searches:
- OpenSearch node query cache
- Redis keyed by search term
- CDN cache
GET /searchfor ~30β60s (works when same query params; breaks with personalized ranking or high-cardinality params like exact lat/long)
Real-time seat map + surge handling
Stale seat map: user loads page; seats sell out in seconds β clicks show error.
Options:
- Long polling β cheap, good for short sessions on page
- SSE (Server-Sent Events) β server pushes seat updates to client (unidirectional; enough here). WebSockets possible but overkill.
Popular events: page loads, seats vanish instantly β bad UX.
Virtual waiting queue (Redis sorted set by arrival time, or random for fairness):
- Millions hit at once β enter queue message instead of event page
- Release users in batches as capacity allows (e.g. per seats booked)
- Notify via SSE when admitted β then book
Simple, creative choke point β not always the most complex tech.
Scaling reads
- API Gateway + services scale horizontally (managed LB)
- Cache event/venue/performer in Redis (rarely change) β view API only hits DB for dynamic tickets
- Shard Postgres if math shows need (shard key discussion:
eventIdvsvenueIdfor geo)
Math tip: only do back-of-envelope estimates when results change the design β not as a checkbox at the start.
DDIA connections
Patterns that echo Designing Data-Intensive Applications:
- Derived data β Elasticsearch index maintained from source of truth (Ch. 11 CDC, data integration)
- Logs/streams β CDC as change stream from OLTP DB
- Consistency β strong guarantees where business requires it (booking), relaxed where OK (search)
- Caching β trade freshness for read latency on hot paths
Key takeaways
- No double booking drives strong consistency on the booking path; search/view can favor availability
- Two-phase booking (reserve β pay β confirm) is standard; model APIs accordingly
- Redis TTL lock beats cron for 10-minute holds β senior differentiator
- Elasticsearch + CDC for search; not dual-primary with Postgres
- Virtual waiting queue for celebrity-event surges
- SSE + caching for seat map freshness and read-heavy traffic
- Specify NFRs in problem context, not as generic buzzwords