System requirements
Functional:
user can view ticket for an event
user can view event
user can book a ticket for an event
user can search for a event
Non-Functional:
highly Consistency as one ticket can only be book and purchase by one user.
highly available, consistency >> availability
low latency for better user experience.
read > write
need to handle double booking scenarios
Capacity estimation
1 million users and DAU 50, 000. Assume 1% book ticket. 5000 booked ticket.
50, 000 DAU makes 10 queries daily 50 QPS.
100kb per event and 1000 event per day
10M which is nothing.
API design
GET v1/ticket={ticketId}
return ticket
GET v1/event={event}
return list of eventIDs
GET v1/search
parameter : artist, location, dateTime
return list of eventIDs
POST v1/book-{ticketID}
return status of booking 400s 200s
all above has to pass user information at JWT header
Database design
use SQL since ACID.
Ticket:
-ticketId
-price
-artists
-dateTime
-seats
Event:
-eventId
-time
-location
-artist
User
-userId
High-level design
write path: client request to API gateway(handle authentication, rate limiting, load balancing) , to booking service, booking result return to client and save to dababase.
booking service use 3rd party payment like paypal/stripe to process payment.
read path, client request to API gateway(handle authentication, rate limiting, load balancing), to query service, to database , then return result to client.
Request flows
write path: client request to API gateway(handle authentication, rate limiting, load balancing) , to booking service, booking result return to client and save to dababase.
read path, client request to API gateway(handle authentication, rate limiting, load balancing), to query service, to database , then return result to client.
Detailed component design
leveraging elastic search and inverted index for event search. use CDS capture data change - make string out of change of database and consume the string to elastic search.
To improve latency:
1, cache top search in elastic search.
2, use CDN
how to ensure consistency between database and cache? we could use 2 phased commit.
handle popular event: cache popular event.
sharding,
data is small, considering future events, we could shard by geolocation and eventid.
1, user double click
solution 1, handle at client side to grey out submit button. down side is client side may disable it.
solution 2, handle at server side using idempotent Key. when booking button clicked, service generate idempotent key associated with booking, and when booking service try to book, it check if idempotent key already in the system.
2, double booking issue - multiple user trying to book the same ticket at the same time.
solution 1, use lock, but lock has hard to scale even distributed lock and intruduce latency. hard to manage unlock time,
use redis cache feature LLT, once ticket booked by one user, it will be added to LLT cache. When other people trying to book, it will first check if it in LLT cache, if its not in TTL cache then it's available to book. After certain amount time, if use did not payment, it got removed from LLT cache.
Failure scenarios/bottlenecks
redundancy
if server fail, secondary replaces it. if master database fail, one of the slave become master.
Future improvements
1, we could use long pulling to handle handle seat availability realtime for better user experience
2, implement chock point- virtual waiting queue for situation of million people fighting for a popular ticket like superbow or taylor swift ticket.