← Back to portfolio

System Design

Ticketmaster — High-Level Design

A walkthrough of how I'd design an event-booking platform like Ticketmaster, BookMyShow, or District — from a single server to microservices, a CDC-backed search index, Redis seat locks, and a waiting queue for sold-out on-sales. Below is the design, step by step.

System DesignCDCElasticsearchRedisKafkaMicroservices
  1. 01

    Requirements, API & Day 0

    Functional needs are search, view event details, and book. Non-functional ones matter more here: strong consistency so the same seat is never sold twice, reads far outnumber writes, and the system must absorb search surges when a popular event drops. Day 0 is a single server and one Postgres — events, venues, and tickets in three tables. Fine to start; it will not survive a Taylor Swift on-sale.

    Requirements, API & Day 0
  2. 02

    Day 100 — Microservices

    Split behind an API Gateway: a Search service, an Event CRUD service (create/update events and seats), and a Booking service (tickets + payments). All three still share one database. Postgres can answer search queries, but it is not built for fuzzy, geo, and faceted search at read-heavy scale — that is where Elasticsearch / OpenSearch comes in.

    Day 100 — Microservices
  3. 03

    Search Index via CDC

    Search reads from Elasticsearch; Event CRUD and Booking write to Postgres as the source of truth. Changes flow out through CDC: Postgres WAL → Debezium → Kafka → Elasticsearch. Writes stay strongly consistent; search is eventually consistent — the right trade-off when read RPS dwarfs writes.

    Search Index via CDC
  4. 04

    Read Path vs Write Path

    Users hit the gateway, then either Search (Elasticsearch) or Event CRUD / Booking (Postgres). CDC keeps the index in sync so the search cluster never talks to the transactional store. With that split in place, the remaining hard problem is the booking flow itself.

    Read Path vs Write Path
  5. 05

    Reserving a Seat — Redis TTL

    POST /reserve must lock a ticket so two users cannot hold the same seat. A DB status column plus a cron to expire 10-minute-old holds works, but it is slow and easy to get wrong. Redis is a better lock: SET the ticket key with a 10-minute TTL. Confirm via Stripe / Razorpay webhooks — not the frontend — then delete the key and persist the booking. If payment never lands, the key expires and the seat is free again.

    Reserving a Seat — Redis TTL
  6. 06

    Booking Service + Payments

    Booking now talks to three things: Postgres (source of truth), Redis (short-lived seat locks), and Stripe / Razorpay (charges). Webhooks confirm payment server-to-server, so a closed tab or dropped network cannot leave a seat stuck in limbo.

    Booking Service + Payments
  7. 07

    Waiting Queue for Mega Events

    A Taylor Swift or Arijit Singh on-sale will melt the booking service if everyone hits /reserve at once. Users POST /join, get a per-user token (so a shared URL cannot skip the line), and the frontend polls admission. An admission service lets the next person in only when a slot frees — e.g. capacity 100, user 35 finishes, user 101 enters.

    Waiting Queue for Mega Events
  8. 08

    Final Architecture

    The full picture: Search → Elasticsearch, Event CRUD → Postgres, Booking behind a Kafka waiting queue with Redis locks and payment webhooks. CDC (WAL → Debezium → Kafka → ES) keeps search fresh. Reads scale independently; writes stay consistent; the queue absorbs the on-sale spike.

    Final Architecture
← Back to portfolio