Sitemap

Designing a Scalable Ticket Booking System Like BookMyShow

3 min readDec 2, 2025

--

How millions of users search events, pick seats, and pay — without double booking.

🌄 Imagine This…

It’s Friday evening. You open BookMyShow to book two seats for the latest blockbuster.
Within seconds:

  • You search for the movie,
  • Select a theatre and showtime,
  • Pick two seats,
  • Pay online,
  • And receive a digital ticket.
  • Millions of people perform the same operations at the same time, yet:
  • No two users get the same confirmed seat.
  • Search always feels fast.
  • Payments and bookings remain consistent.

Behind this smooth experience lies a beautifully orchestrated distributed system.

Today, let’s break down how a Ticket Booking System (just like BookMyShow) can be designed from scratch — based entirely on the architecture presented in diagram.

Press enter or click to view image in full size
Ticket Booking

1.Functional Requirements :

🔍 Search Events

  • Search movies, events, locations, shows.

📅 Search Based on Filters

  • By date, location, cast, genre, cost, etc.

💺 Seat Selection

  • User should see real-time available seats.

🔒 Seat Locking

  • Selected seats must be temporarily blocked before payment.

💰 Booking & Payment

  • Completing payment confirms seats.
  • Cancelled/failed payments must release seats.

2. Non-Functional Requirements

⚡ Low Latency Search

  • Search needs to feel instant → ~50–150ms.

🟢 High Availability

  • System must be available even during peak releases.

🔄 Eventual Consistency in Search

  • Search results can tolerate slight delays — but seat booking CANNOT.

🧵 Strong Consistency During Seat Booking

  • Two users must never get the same seat.

⚙️ Elastic Scalability

  • System must handle traffic spikes (think Rajnikanth/Marvel releases!).

3. Entities

Event

{
"eventId": "…",
"eventName": "…",
"location": "…",
"showTime": "…",
"ticketPrice": 250
}

Seat

{
"seatId": "…",
"status": "available | locked | booked",
"userId": "optional",
"lockExpiry": "timestamp"
}

Booking

{
"bookingId": "…",
"eventId": "…",
"userId": "…",
"seats": ["A1", "A2"],
"status": "pending | confirmed | failed"
}

4. API Surface :

Event APIs :
- GET /events
- GET /events/{eventId}

Seat API :
- GET /events/{eventId}/seats
- POST /events/{eventId}/seats/lock

Booking API
- POST /book
- GET /booking/{bookingId}

Payment API
-
POST /booking/{bookingId}/payment

Get Soma Sundhar Reddy’s stories in your inbox

Join Medium for free to get updates from this writer.

5. High-Level Architecture :

  • User → Search Service → ElasticSearch
  • User → Seat Service → Cassandra DB
  • User → Booking Service → MySQL / Postgres

This ensures:

🔥 Fast reads (ElasticSearch)

🔐 Strong consistency for seats (PostgreSQL/Relational DB)

🔄 Highly Available (Cassandra/NOSQL)

6. Deep Dive Architectural Flow :

Let’s walk through the entire real-world workflow end-to-end.

1️⃣ Searching for Events

  • User → Search Service → ElasticSearch
  • ES stores denormalized documents: eventName, showTime, cast, genre, cost, location, screens…
  • Search service queries ES → returns results instantly.

Why ElasticSearch?

  • Full-text search
  • Filters + facets
  • Sub-second response time

2️⃣ Viewing Seats for a Show

  • User → Seat Service → Cassandra DB
  • Cassandra stores the seat map:
seatId | status | userId | lockExpiry

Why Cassandra?

  • High write throughput
  • Fast updates with TTL
  • Perfect for storing rapidly-changing seat states

3️⃣ Seat Locking (Most Critical Part)

  • Seats can be locked for a temporary duration (typically 3–10 minutes).

Flow:

  • User selects seats
  • Seat Service validates availability
  • Writes status = locked with TTL

Example lock document:
{
“seatId”: “A1”,
“status”: “locked”,
“userId”: “U123”,
“lockExpiry”: 120000
}

Why TTL?

  • Cassandra automatically unlocks seats after expiry → avoids orphan locks.

4️⃣ Booking Service Creates Booking Record

  • Seat Service → Kafka → Booking Service
  • Booking Service reads seat-lock events:
  • Creates booking entry in MySQL/Postgres
  • Marks booking as pending
  • Sends event to Payment Service
  • Relational DB is chosen because:

✔ strong consistency
✔ multi-row transactions
✔ payment-related ACID ops

5️⃣ Payment Flow:

  • User completes payment → Payment Service → Booking Service

Booking Service:

  • Validates payment
  • Confirms booking
  • Updates seats → status = booked
  • Sends confirmation to user
  • Pushes event to search → ES updates show availability

6️⃣ What If Payment Fails?

  • Booking → failed
  • Seat TTL expires → automatically becomes available
  • No manual clean-up needed

--

--

Soma Sundhar Reddy
Soma Sundhar Reddy

Written by Soma Sundhar Reddy

I explore new tech like a movie buff discovering fresh genres. Here, I share my learnings and stories from the ever-evolving script of my tech journey."