Design TicketMaster
Design TicketMaster
I think this is quite an interesting usecase to design ticket master. Before we go into understanding the system design of ticket master, let's think about what exactly ticket master is. Ticket master is an app where you can book tickets, view the seat map for an event, and also reserve the tickets. You can search for certain events. For example, you search, "Taylor Swift" and you can get results related to the taylor swift events. There are other things, like you can sort these events according to the timestamp, etc. But on a higher level, these are the things that you can do.
Functional Requirements
1. Search for an event
2. View and event and the seat map
3. Book a ticket within the event
Non-functional Requirements:
1. For search you want high availability
2. For booking you want high consistency. i.e When a user wants to view the seats, he/she should get only the seats that are available. If 2 users are viewing the ticket map, the ticket map should get updated in real time.
Core-Entities:
1. Event : There needs to be an event entity that holds the information related to the event. Like eventId, eventName, eventDescription, ticketMap, eventPerformer.
2. Ticket: This is the basic unit of ticket. TicketId, UserId, Status, Price, TicketLocation (like 31B, 31C, etc). , eventId
3. Performer: PerformerId, performername, performer type - like a musician, actor, comedian, etc. events
4. Booking: BookingId, price, userId,
5. User: UserId, UserName, User details,
API Design:
Now that we have the Core entities needed, we want to think of the API design from the user perspective. Let's go with the flow of the app. The user opens the app. One thing is that the user enters as a guest and just wants to buy the ticket. You will see a search bar on top.
This is the current home page of ticket master. The UI icons are okay. You will have a navigation bar up. What's important for us is the backend api design that we care about. We want to have a search bar, that's parameterized by daterange, search query, and the location or the zipcode. This should return us a list of events from that area.
I just searched for events in my city and here is the list of events we got. So the search worked.
Search:
GET events?searchTerm={}&&location={}&&startDate={} && endDate={}
This is the API we have for search and the response would be :
{
events: [eventId1, eventId2, .... ] - > Sorted by timestamp
}
I am not over optimizing the design right now as I am just laying out the structure of the design and the design will evolve as we move forward.
FindTickets:
Let's say I do a find tickets click.
As you can see I see a whole ticket map when I hover over a certain area, it gets selected and that ticket will be bought. You are seeing the available tickets in blue area and the stadium map as well. Which I believe is great. What's interesting is that different tickets are in different price range.
GET findTickets/?eventId={}. As you can see on the right side, you see a list of tickets available for the event:
So, when you do a find ticket you get the list of available tickets. Returns:
{tickets: [ticketId, ticketId2, ... ticketIdn]}
So the response you get is a list of available tickets and these tickets are the one you want to buy. Moreover when you click on the blue area in the ticket master app,
Returns all tickets from that area.
3. Reserve a ticket:
PUT: ReserveTicket : /event = {eventId} && ticket={ticketId}
If you can reserve the ticket you will return an 200 response and you can store that reserved ticket in a cache with a TTL of 5 minutes or 10 minutes whatever you feel would be the best TTL.
4. Buy a ticket:
POST : Buyticket/ event={eventId} && ticket={ticketId}
When the user clicks on buy the ticket, it goes to the payment page, and our api will call an external service like stripe and make sure that the payments are handled by stripe. This way they will handle the payment and the seat will go from reserved to booked in the status.
High level design:
This is the high level design and there are a few parts to it:
1. Client: This is the web interface that the client sees.
2. API Routing: This is the layer where we will do the authentication, authorization and then route the request to the requested API
3. Search : This service will go to the DB and get the respective data from the DB. For example, if you search for taylor swift, it will do a query on the postgres database to find events where the performername is taylor swift or where the query is taylor swift. Although this is not efficient we will come up with an improved design later on.
4. Book an event: This is the service that will handle the reservation and the booking for an event ticket. For example, if the user clicks on the ticket the ticket will be reserved for some period of time. This time will be determined by the TTL of a redis cache and eventually we will think more in detail about it in the deep dive.
5. Find tickets page: This is when you click on an event, you will find all the tickets that are available for a given event.
For fetching all of these data, it's a very simple logic that you will have to query in the db and you will get the data. But what about efficiency? Would that be really efficient. The answer to this is not really. We know that whenever you are doing a search, the best way to search is the elastic search db.
Deep Dive:
1. Search: Instead of going to the post gres database we will do search inside elastic search. The way we store events in elastic search is this. We will have an event name while we create an event right. We take the letters in the event name and store that in elastic search. We also store the description inside elastic search.
For example, eventName: Taylor Swift Concert
eventDescription: This is a taylor swift concert and it will be big.
Taylor: [event1, event5, event10....] Now when a user queries for taylor swift, the algorithm will be able to return event1,5 and 10.
2. Booking an event: here we need a cache to make sure that we store the booking details like reserved in a redis ttl. When the user clicks on a particular ticket to buy, we first check that if it's reserved or not. This is by querying the redis db. That's a quick call because its cache. If it is there we show him the payments page.
When the user clicks on buy ticket, here we call stripe and once the call stripe receives the payment, it triggers a callback to us. Basically, we can have a webhook here to connect to stripe and receive a callback that the payment is received. Once the payment is received we can change the ticket status to booked.
3. Find tickets: Now when we want to view the tickets for a particular event, we can simply query the database and get the tickets. Moreover, for performance increase we can also cache these available tickets.
What is a webhook?
A webhook is an automated message sent from one app to another when a specific event occurs, allowing for real-time communication and data synchronization without constant polling. Instead of an application repeatedly checking for updates, the originating application "pushes" the data to a predefined URL (a callback URL) provided by the receiving application as soon as the event happens.
So as you can see it is basically an automated message sent from one app to another when a specific event occurs. Allowing for realtime communication. So the original application once the work of payment is done, it pushes the data to the callback url saying that the payments is done.
Comments
Post a Comment