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
  • email
  • 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
  • email
  • date


High-level design

  1. Load balancer. The LB like Nginx will make our system much more scalable and may do some other jobs like rate limiting
  2. 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
  3. Cinema database. The main database that owns all the tables. We will chose relational database like PostgreSQL here
  4. Search database. Database for efficient search of movies and cinemas. We will use database that supports full-text search like ElasticSearch
  5. 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
  6. External payment service. We will use external payment service. The integration service will interact with it via HTTPS API
  7. Message broker. The broker like Kafka will be used the asynchronous interactions between services
  8. SMTP server. The server that sends emails with tickets to users



Request flows

Search

  1. The reqeust comes to LB and is sent to API Service
  2. API service retrieves all the movies with the available showtimes and seats from search database
  3. API service filters the shows based on the information about available seats in the cinema database
  4. API service returns available shows to the user

Buying tickets

  1. The request PUT /reserve goes to API service through LB
  2. 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
  3. Reservation status = reserved
  4. Seats status = reserved
  5. API service count the price and sends a request for payment url to the integration payment service. The request goes to payment service
  6. So the API service returns payment link to the user
  7. User makes a payment
  8. Payment service sends a request to the integration payment service
  9. integration payment service sends payment information to the API service via message broker
  10. When API service receives confirmation of the payment, it creates tickets and sends them to the users email using SMTP server
  11. Reservation status = purchased
  12. 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

  1. We need ACID transactions support to handle concurrent reservations requests
  2. The relational database structure is very flexible
  3. 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.