The Question
Design

Scalable Cinema Booking System

Design a high-concurrency ticket reservation system for a global cinema chain. The system must support real-time seat availability, prevent double-booking through distributed locking, handle payment-triggered state transitions, and scale to 10M+ daily active users during peak blockbuster releases.
PostgreSQL
Redis
Kafka
CDN
JWT
Stripe
Questions & Insights

Clarifying Questions

Scale and Traffic: What is the expected scale in terms of Daily Active Users (DAU) and peak QPS during blockbuster movie releases? (Assumption: 10M DAU, 50k QPS peak during major releases).
Concurrency & Consistency: Is there a requirement for strict "exactly-one" seat booking? (Assumption: Yes, no double-booking is allowed; high consistency for seat selection is paramount).
Booking Window: How long should a seat be held while the user completes the payment? (Assumption: 10 minutes temporary lock).
Geographic Distribution: Is this a global system or localized to a specific country? (Assumption: Multi-region support for a large country, e.g., US or India).
Payment Integration: Should we handle payments or integrate with 3rd parties? (Assumption: Integrate with external providers like Stripe/PayPal).

Thinking Process

Core Strategy: The system's primary challenge is managing high-concurrency seat contention. We will use a Distributed Locking mechanism for temporary seat holds and a Relational Database with ACID properties for the final transaction.
Progressive Approach:
How do we prevent two users from selecting the same seat simultaneously? (Redis-based distributed locks with TTL).
How do we ensure the ticket is issued only after payment? (Two-phase state machine: Pending -> Paid -> Confirmed).
How do we handle massive read traffic for showtimes? (Read-through caching for movie metadata and schedules).
How do we ensure the system stays responsive during high-demand "flash-sale" scenarios? (Asynchronous notification/ticket generation and request queuing).

Bonus Points

Transactional Outbox Pattern: Using CDC (Change Data Capture) or an Outbox table to ensure the Notification and Ticket generation services are eventually consistent with the Booking DB without using heavy distributed transactions.
Seat Map Optimization: Storing seat maps as Bitmaps or compressed JSON blobs to reduce DB I/O and latency when fetching theater layouts.
Idempotency Keys: Implementation of client-side generated idempotency keys to prevent duplicate charges and bookings during network retries.
Dynamic Pricing Support: Architecture allows for a pricing engine component that can adjust prices based on demand and time-to-show without impacting core booking latency.
Design Breakdown

Functional Requirements

Users can search for movies by city, date, and cinema.
Users can view a real-time seat map for a specific showtime.
Users can select and "lock" seats for 10 minutes.
Users can complete payment to confirm the booking.
Users receive a digital ticket (QR code) via email/app.
Admins can add movies, cinemas, and showtimes.

Non-Functional Requirements

High Consistency: Zero tolerance for double-booking.
High Availability: Search and browse must be 99.99% available.
Low Latency: Seat selection and booking response under 200ms.
Scalability: Handle sudden spikes during blockbuster launches.

Estimation

Users: 10M DAU.
Daily Bookings: ~500k tickets/day.
Peak QPS (Search): 10M users browsing -> ~20k QPS.
Peak QPS (Booking): ~5k QPS during "opening night" sales.
Storage: 1k cinemas 10 screens 5 shows * 200 seats = 10M show-seats/day. Data retention for 2 years ~ 5TB.

Blueprint

Concise Summary: A microservices-based architecture utilizing an RDBMS for transactional integrity and Redis for high-speed temporary seat reservations.
Major Components:
API Gateway: Entry point for authentication, rate limiting, and request routing.
Search Service: High-performance read-layer for movie metadata and showtimes.
Booking Service: Orchestrates the seat-locking logic and booking lifecycle.
Payment Service: Interfaces with external payment gateways and updates booking status.
Notification Service: Asynchronously handles ticket delivery via Kafka.
Simplicity Audit: This design avoids complex distributed transaction coordinators (like 2PC) by using a state-machine approach in the database and a messaging queue for downstream side effects.
Architecture Decision Rationale:
Why this architecture is the best for this problem?: The separation of Search and Booking allows the system to scale the high-volume/low-consistency search traffic independently from the low-volume/high-consistency booking traffic.
Functional Requirement Satisfaction: Meets all requirements from browsing to ticket issuance.
Non-functional Requirement Satisfaction: Uses Redis for low-latency locks and RDBMS for the required consistency level.

High Level Architecture

Sub-system Deep Dive

Edge (Optional)

Content Delivery & Traffic Routing: Static movie posters and trailers are served via CDN to reduce origin load.
Security & Perimeter: API Gateway handles JWT validation and implements Leaky Bucket Rate Limiting to prevent bot-driven "seat scraping." SSL termination occurs at the Load Balancer level.

Service

Topology & Scaling: Stateless microservices deployed across Multiple Availability Zones (Multi-AZ). Auto-scaling is triggered by CPU utilization and Request Count per Target.
API Schema Design:
POST /v1/bookings/reserve: Reserve seats.
Request: { showtimeId: string, seatIds: string[] }
Response: { bookingId: string, expiry: timestamp } (Idempotency key required).
POST /v1/payments/confirm: Finalize booking.
Request: { bookingId: string, paymentToken: string }
Resilience & Reliability: Circuit breakers (e.g., Resilience4j) protect the Booking service from slow Payment Gateway responses.
Security: Service-to-service communication secured via mTLS.

Storage

Access Pattern: Heavy reads for showtimes; highly transactional writes for bookings.
Database Table Design (Booking DB):
Movies: id (PK), title, duration, rating.
Showtimes: id (PK), movie_id, theater_id, start_time, base_price.
Seats: id (PK), theater_id, row, number.
Bookings: id (PK), user_id, showtime_id, status (PENDING, PAID, CANCELLED), total_amount.
Showtime_Seats: id (PK), showtime_id, seat_id, booking_id, status (AVAILABLE, LOCKED, SOLD). (Composite index on showtime_id and seat_id).
Technical Selection: PostgreSQL with RDS for managed HA. Rationale: Strong ACID support is non-negotiable for seat status.
Distribution Logic: Partitioning Showtime_Seats by showtime_id to localize queries for a specific movie screening.

Cache

Purpose & Justification: Redis handles Distributed Locking for the 10-minute seat hold to prevent DB contention during the "selection" phase.
Key-Value Schema:
Key: lock:showtime:{id}:seat:{id}
Value: user_id
TTL: 600 seconds.
Failure Handling: If Redis fails, the system falls back to DB-level SELECT FOR UPDATE (performance degraded but consistent).

Messaging

Purpose & Decoupling: Kafka decouples the critical booking path from non-critical tasks like sending emails or generating PDF tickets.
Event Schema: BookingConfirmedEvent { bookingId, userId, seatDetails, qrCodeData }.
Technical Selection: Kafka for high throughput and durability, allowing message replay if the notification service is down.
Wrap Up

Advanced Topics

Trade-offs (PACELC): We choose Consistency (C) over Availability (A) during the booking phase. If the seat database is partitioned/unavailable, we cannot take bookings. However, for Search, we prioritize Availability.
Reliability: A "Cleanup Worker" is implemented to scan the Showtime_Seats table for LOCKED seats with expired timestamps that weren't cleared by the Payment service, returning them to AVAILABLE.
Bottleneck Analysis: The Showtime_Seats table is a potential hot spot. Optimization: Use a local cache for "Fully Booked" shows to stop traffic before it hits the DB.
Security: PII (User emails/phones) is encrypted at rest using AES-256. Payment data is never stored locally (PCI-DSS compliance via Stripe tokens).