Skip to content

Latest commit

 

History

History
105 lines (62 loc) · 5.29 KB

File metadata and controls

105 lines (62 loc) · 5.29 KB

The prompt is one of the most notorious in the industry: "Design Ticketmaster" (or BookMyShow). It tests everything: massive read-heavy traffic, extreme write-heavy burst traffic, and strict transactional consistency.

Let's walk through the framework to ace this.


**Step 1: Requirements & Scope **

Never start drawing boxes immediately. You must define the boundaries of the system.

Functional Requirements:

  1. Users can view upcoming events and search for concerts.
  2. Users can select seats and book tickets.
  3. The system must handle highly anticipated events (e.g., a Taylor Swift concert dropping at exactly 10:00 AM).

Non-Functional Requirements:

  1. High Availability (Reads): Browsing events must never go down.
  2. Strict Consistency (Writes): We absolutely cannot double-book a single seat.
  3. High Concurrency: The system must handle massive burst traffic (The "Thundering Herd" problem).

**Step 2: Back-of-the-Envelope Math **

We need to prove to the interviewer that a standard database will melt, justifying our complex architecture.

  • The Scale: Assume 10 million active users.
  • The Burst: For a mega-concert, assume 1 million users hit the "Book" button within a 60-second window for a stadium with 50,000 seats.
  • Write QPS (Peak): $\frac{1,000,000 \text{ requests}}{60 \text{ seconds}} \approx 16,666 \text{ QPS}$.
  • Architectural Decision: 16k write QPS on a single relational database table (seats) doing row-level locking will cause catastrophic deadlocks. We must decouple the booking request from the database write.

Step 3: High-Level Architecture

We lay out the broad strokes of the read and write paths.

The Read Path (Browsing Events):

  1. CDN & Edge Cache: 99% of traffic is just looking at event images and dates. This never hits our backend. It is served instantly from Cloudflare/AWS CloudFront.
  2. Search Service: Users searching for "Pop concerts in New York" hit an Elasticsearch cluster. Elasticsearch is optimized for fuzzy text search and geo-queries, isolating read-heavy search traffic from our transactional databases.

The Write Path (Booking):

  1. API Gateway: Routes the POST /book request.
  2. Booking Service: A stateless microservice that orchestrates the transaction.
  3. The Database: A relational database (PostgreSQL or CockroachDB) for absolute ACID compliance on the final ticket purchase.

Step 4: Deep Dive & Core Conflicts

The interviewer will now drill into the hardest part of the system: The 10:00 AM Ticket Drop.

Conflict 1: The Thundering Herd

At 9:59 AM, traffic is 100 QPS. At 10:00:00 AM, traffic is 500,000 QPS. If we let 500k requests hit our internal network, our microservices will crash.

The Solution: The Virtual Waiting Room

  • We push the logic out to the Edge (API Gateway/CDN level).
  • Before the API Gateway even talks to the Booking Service, it checks a Redis Token Bucket.
  • If the stadium has 50k seats, we only allow 50,000 active booking sessions at a time. The other 450,000 users are instantly redirected by the Gateway to a static HTML "Waiting Room" page that polls every 30 seconds. This shields our internal database entirely.

Conflict 2: The Concurrent Seat Lock

User A and User B both get through the waiting room. They both click on "Seat 5, Row F" at the exact same millisecond.

The Solution: Distributed Redis Locking

  • We do not lock the row in Postgres yet. We use Redis for extreme speed.
  • The Booking Service runs a Lua script in Redis: SET lock:event123:seat5F "User_A" NX PX 600000.
  • NX means "Only set if it does not exist".
  • PX 600000 sets a 10-minute expiration (Time-To-Live).
  • The Result: User A's request hits Redis a microsecond faster. They get the lock. User B's request gets a 0 from Redis, and the UI instantly says "Seat taken."

**Conflict 3: The Payment Saga **

User A has the seat locked in Redis for 10 minutes. They proceed to enter their credit card.

The Solution: Event-Driven State Machine

  • If User A pays successfully within 10 minutes:

  • The Payment Gateway fires a PaymentSuccess event to Kafka.

  • The Booking Service consumes it, officially writes the UPDATE seats SET status='SOLD', user_id='A' into PostgreSQL, and deletes the Redis lock.

  • If User A closes their browser or the credit card declines:

  • The 10-minute Redis TTL automatically expires. The lock vanishes.

  • A background worker (or Kafka delayed message) checks Postgres. Seeing the seat is still "AVAILABLE", it does nothing. The seat naturally appears as available to the next person in the Waiting Room.


Step 5: Bottlenecks & Trade-offs

To get the "Strong Hire" rating, you must proactively critique your own design.

  • "Our Postgres database is a single point of failure for the final write. To mitigate this, I would shard the Postgres database by event_id. Since a user only books tickets for one event at a time, we never need to do cross-shard JOINs, allowing us to scale the write throughput horizontally."
  • "Redis is currently our single point of truth for active locks. If the Redis master node crashes, we could lose the locks for users currently checking out. I would deploy Redis in a clustered setup with strictly synchronous replication for the lock keys to ensure high availability."