System requirements
Functional:
- Search movies
- View showtimes
- Select available seats
- Make payments
- Receive digital tickets
Non-Functional:
- 100 movies
- 20 cinemas
- 10 k active users
- 5 searches per day
- 2 tickets bought per day
Capacity estimation
We definitely have not big amount of movies and cinemas. And users make not so many purchases. So the amount of data will not be a big problem.
- 0.5 RPS on search
- 0.2 RPS on ticket purchase
API design
Search movies
Method – GET /search
Input:
- query – string
- date_from – datetime
- date_to – datetime
Output:
- Array of movies
- movie_id
- array of available cinemas
- cinema_id
- array of available dates
Get available seats
Method – GET /seats
Input:
- movie_id
- cinema_id
- date
Output:
- Array of available seats
Reserve seats
Method – PUT /reserve
Input:
- movie_id
- cinema_id
- date
- idempotency_key
- seat_ids – array of seat ids
Output:
- payment URL
Database design
Cinema table
- cinema_id
- title
- image_url
- seats – json field with the hall seats locations
Movie table
- movie_id
- title
- description
- image_url
Shows table
Table that shows movies of a specific movie in a specific cinema on a date.
- show_id
- movie_id
- cinema_id
- hall_id
- date – the date of movie is shown in the cinema
Seats availability table
- show_id
- seat_id
- price
- status – available/reserved/purchased
Reservations
- show_id
- seats – array of seat ids
- status – reserved/purchased/cancelled
- date
High-level design
- Load balancer. The LB like Nginx will make our system much more scalable and may do some other jobs like rate limiting
- API service. The main business logic service that provides API for users. This service handles all the users load and performs main business logic operations
- Cinema database. The main database that owns all the tables. We will chose relational database like PostgreSQL here
- Search database. Database for efficient search of movies and cinemas. We will use database that supports full-text search like ElasticSearch
- Integration payment service. Service that will be focused on integration with payment service. This service will encapsulate all the logic of interacting with the external service
- External payment service. We will use external payment service. The integration service will interact with it via HTTPS API
- Message broker. The broker like Kafka will be used the asynchronous interactions between services
- SMTP server. The server that sends emails with tickets to users
Request flows
Search
- The reqeust comes to LB and is sent to API Service
- API service retrieves all the movies with the available showtimes and seats from search database
- API service filters the shows based on the information about available seats in the cinema database
- API service returns available shows to the user
Buying tickets
- The request PUT /reserve goes to API service through LB
- API service in one transaction creates new reservation and changes the availability of the seats in the show. If the seats are not in the available status by this time, the API service will return 409 error, because the seats are already reserved. The client app will offer the user to choose different seats
- Reservation status = reserved
- Seats status = reserved
- API service count the price and sends a request for payment url to the integration payment service. The request goes to payment service
- So the API service returns payment link to the user
- User makes a payment
- Payment service sends a request to the integration payment service
- integration payment service sends payment information to the API service via message broker
- When API service receives confirmation of the payment, it creates tickets and sends them to the users email using SMTP server
- Reservation status = purchased
- Seats status = purchased
Detailed component design
API service will have 2 separated physical services. One will handle users requests. And the second one will process message broker messages.
Trade offs/Tech choices
Nginx for LB
Nginx has a big active community, so it is common choice for the LB.
PostgreSQL for the cinema database
There are few reasons for choosing relational database for the cinema service
- We need ACID transactions support to handle concurrent reservations requests
- The relational database structure is very flexible
- PostgreSQL has big active community
Kafka for message broker
We need guaranteed ascyncronous communication between microservices. Kakfa is quite popular choice for this goal
Elasticsearch for search database
We need to have full-text search for our films. ElasticSearch database is very efficient for this goal
Failure scenarios/bottlenecks
The main bottleneck here is Cinema database. It will handle main write and read load.
But the main parts of the architecture is asynchronous and all the services are stateless. So the system will be highly available.
Future improvements
For more guarantee in asynchronous interactions between services we may use outbox pattern in future.
If the cinema database if the main point of failure, it can be made more available in future. But the CAP theorem trade-off will come in to place here.