System requirements
Functional:
- User Registration and Authentication
- Movie Listings
- Seat Selection
- Payment Processing
- Ticket Confirmation and Retrieval
- Cancellation and Refund Processing
- Admin Dashboard
- Notifications
- Search and Filter Functionality
Non-Functional:
- Scalability: able to handle high traffic;
- Consistency: the seat should not be selected by 2 people at the same time;
- Privacy and security: certain actions should be authenticated;
- Availability the system should be up 99.99% of the time.
Capacity estimation
There could be 10k to 100k DAU.
The peak traffic is 3k to 5k QPS.
The payment info would be 10k * 5KB per day, storage: 1.5 GB every year.
Movie listing require CDN to store videos and images.
10k listing * 200MB = 2TB storage
API design
- Movie Listing: GET /listing
- Response: {"movie_info", "thumbnail", "availability"}
- Seat selection: POST /select_seat
- Request: {"user-id", "movie-id", "date-time", "location", "seat"}
- Response: {"selection-status", "order-id", "expire_at"}
- Payment: POST /payment
- Request: {"user-id", "order-id", "paymen-info"}
- Response: {"payment-status"}
- Cancel: POST /cancel
- Request: {"user-id", "order-id"}
- Response: {"cancellation-status"}
- Search: GET /search?query=
- Response: {"movie_info"}
Database design
- Movie: int movie_id(auto increment primary key), String name(index support fulltext search), String intro(index support fulltext search), String thumbnail_url, String trailor_url, String memo
- MovieAvailability: int availability_id(auto increment primary key), int movie_id(Foreign key to movie.move_id), int location_id(Foreign key to location.location_id), DateTime date_time
- Seat: int seat_id(primary key), int availability_id(foreign key to MovieAvailability.avalability_id), int seat_number, Enum Status(available, pending, sold)
- Location: int location_id(primary key), String location
- Order: int order_id(primary key), int availability_id(foreign key to MovieAvailability.avalability_id), DateTime created_at, int seat_id(foreign key to Seat.seat_id), Enum payment_state(initiated, pending, fail, success)
- User: int user_id(primary key), String email, String salt, String hash_password, datetime created_at
High-level design
At high level we have the following components:
- API gateway: handles load balancing, authentication, rate limiting, service discovery
- Movie service: shows movies available, handles search and filtering on movies, might integrate with recommendation system, shows availability of a movie, and shows available seats, also handles admin modification request
- Order Service: Handles seat selection, order placement, payment processing
- User account management service: Handles registration, login, account management
- Database: stores the data model we described
- Redis Database: stores frequently visited information in cache
Request flows
- User make order flow:
- User send login request
- API gateway forwards request to account management service
- account management service verifies user account and password from DB, and return login status and token
- User stores token in cookie, sends list request
- API gateway route it to movie service
- movie service query Redis and DB to get Movie lists and availability lists
- (optional) User sends search request or filter request
- movie service builds the query and send to DB, returns result to user
- User send seat selection request
- API gateway route to order service
- order service checks seat availability and change seat status to pending, and return select success to user
- user sends payment info to order service
- order service sneds payment to payment service
- order service inserts order to the table, returns status to the user
Detailed component design
Rate limiting at API Gateway: To balance efficiency and spread load, I suggest to use the sliding window + bucket algorithm for the rate limiting
DB reliability and scalability: To serve the peak traffic, DB should be replicated. Different table has different consistency requirement. i.e. seat table has a strong consistency requirement, so the replication algorithm should be synchronous update. And set the quorum to be high enough to avoid conflicts. The movie table has weaker consistency requirement, so we can implement the eventual consistency.
Orderid grows really fast and multiple order service instance might write at the same time, so we can use the snowflake algorithm to design the order id. The order id is consisted by 3 parts: service-id, timestamp, incremented id.
Trade offs/Tech choices
Writing to the order table ensures consistency over availability. It has a strong consistency requirement, so checking the availability and writing to the table has longer latency to ensure there is no conflict.
Failure scenarios/bottlenecks
The order service and movie service are stateless, so failures can be handled as bringing up new services. The ongoing payment would not be written to the DB until the payment is successful, so it can be reverted.
Future improvements
A/b testing for the recommendation algorithm
Load testing
CI/CD
Different development environment: prod, canary, dev