User can view events and choose tickets with assigned seat
User can search movies
User can book ticket
User can pay the ticket
Admin can add events
Non-Functional:
Latency should be low
Weigh availability over consistency, but for reserving ticket and payment, keep high consistency
Support 50K DAU
Capacity estimation
For booking ticket, we estimate each user books 2 ticket, so daily book request is 100K => QPS = 100 K / 3600 / 24 = 1.2
we assume each user has 5 search request and 10 viewing request, then the total read QPS = 15 * 50K / 3600 / 24 = 9
For storage, assuming we need 100 Byte for each seat info and related theater and movie info, then for one day the storage size is: 100 B * 100K = 10M, if we keep the information for 5 years, then total size: 10M * 365 * 5 = 19G, which should be easily handled by DB
Considering the QPS and we want to keep the system highly scalable, we'll design it as a distributed system
API design
Search
Get
v1/search?query=xxx&user_id=yyy&page=zzz
View event to detail description and seats distribution
Get
v1/event:even_id
Reserve a ticket
Post
v1/reserve
body {auth_token, user_id, ticket_id}
Book a ticket
Post
v1/book
body {auth_token, user_id, ticket_id, card_info}
Admin update event
Post
v1/update/event
body {event_name, description, theater_id, start_time, ticket_count}
Admin update ticket
Post
v1/update/ticket
body {ticket_list [{seat_no, price}, ...{seat_no, price}]}
User can search, view event and book ticket from the client
Admin Client
Admin uses the client to update event and ticket info
Load balancer
Responsible for distributing server request to server, we can use round-robin as the the load balancing algorithm
API gateway / Webapp server
Webapp server returns the web page to the user
API gateway is responsible for routing different api request to corresponding service
API gate is also responsible handle authentication check, rate limiting
Search service
Search service handle user's search request and build a search result event list as response to send back to the user
Event service
Event service handle user's even view request, getting ticket and seat information and send back to the user
Event service also handle admin's request to update event and ticket via API v1/update/event, v1/update/ticket
Booking service
Booking service handle user's request to reserve ticket and handle book ticket by sending payment request to 3rd party payment service such as Stripe to finish booking
3rd party payment service
In our flow, we rely on 3rd party payment service to handle the actual payment, Stripe is one of the popular payment service
Request flows
Searching
User type a query from the client then search, it triggers API v1/search
After the API is routed by load balancer and API gateway, the request is landed on one of search service server
The search service first checks whether there's related events for the query from search cache, if not, then checks events in event table. Matched search results will be send back to the user. If there are pictures or media files related to the description of the event, user client will fetch them from CDN with CDN link from response data to reduce latency
Viewing
User clicks a specific event from search result page
The detail event page will be open with api call v1/event
The page shows seats and tickets info for the event
The v1/event request is handled by event service
The service fetch event info from event table, and fetch ticket info from ticket table then return as response to render on the page
Booking
There are 2 phase of booking: a. reserve the ticket, b. actual booking the ticket
The reserve request is sent as api v1/reserve to booking service and update ticket data in ticket table. The actual booking is sent as api v1/booking to work with 3rd party payment service to finish booking. We'll discuss reserve and booking in more details in the detail design section.
Admin update
Admin can update events and corresponding tickets from admin client with APIs v1/update/event, v1/update/ticket
These APIs are handled by event service, new event will be added into event table, and new tickets will be added into ticket table
Detailed component design
Search
Search DB
We can start with using a SQL query to search related event in search DB. As the QPS and storage estimation we've done previously, it will work well for our current system. If we keep scaling the system, this can be a bottleneck, we can discuss further in the future improvement
Search cache
We use redis as search cache. The key is the query term and the value is a JSON list of events that matches the query. The redis cache can be maintained by daily job from search services to keep most frequently used queries and corresponding events in the cache. As building a search service can be another entire design topic to talk, we just keep the discussion at this level.
Pagination
In order to improve availability, reduce latency and provide better user experience. Pagination is supported for the search request. The page parameter in the request indicates which page should the search service return, we can set each page to return 30 results.
Booking & payment
When user reserve a ticket, the booking service changes the status field in the ticket table to 'reserved' and update the timestamp, we consider the the reserve duration is 1 hour.
When viewing the event by another user, the event service can check the timestamp and status, if the timestamp already passed 1hour duration, then the event service knows it's not reserved any longer and can return the ticket as available
When handle the actual booking request, the booking service send an API request to the payment service, when the payment succeeded, the 3rd party service will send the success response as a registered callback to booking service. Then booking service can update ticket table to set status to 'booked' as well as update the timestamp
Trade offs/Tech choices
Database selection
The QPS and storage can be well handled by SQL DBs and we can easily support horizontal scale by sharding with event id
Another reason we select SQL DB comparing to no SQL DB is that it's easier for us to update ticket status as it's table based
In order to keep high availability we will have replication for userDB, eventDB and ticektDB with master-slave replication. Read request is handled by slave and write request is handled by master. For booking request as we want to keep strong consistency, during the book flow, ticket info read for corresponding ticket_id is blocked until the master finishes write and replicated the latest data to slaves
Failure scenarios/bottlenecks
If search request failed, user will see empty search results, user can retry the search
If booking failed, we need to ensure that the payment did not proceed for the user and return clear instructions to allow user to retry. The ticket status in ticket table should still be in reserved status
Future improvements
Search
To further increase search availability and reduce latency, we can integrate 3rd party search tech such as elastic search