We want to load a feed based on the homepage showing the most important sports news
Real time score update for a sport/event that updates dynamically as the game continues.
We want really low latency on our live data we since the sports event is constantly changing. But in terms of overall player/team stats we actually want to prioritize consistency, so that there are no discrepancies in a game, for example Player A assisted PlayerB in a goal but the data needs to be one single transcation that executes for both or not at all. And so that data is accurate.
Imagine we are designing something like a TSN. With 100 million active users monthly, and lets say an average of 1 billion requests a month. The actual feed would need to support 10000 requests per second assuming Approximately 100000 requests/second.
Assuming there are 10 large sports that we support (NFL, NHL, NBA, Boxing, UFC, Soccer, Baseball etc) and Each sport has about 30 different teams, and each team has 30 different players, thats 10 * 900 = 9000, players of data we need. Each player will have metadata of lets say 10kb. That is 90000kb or 90mb of just metadata related to players, then maybe another 1mb per team, so 100mb of data we need to be updating every couple of minutes as these updates are not as relevant to be live.
We also then need live updates during a game which is 60 players, two teams, location meta data. Lets say 10mb a second to be sure.
GET https://tsn.com/home which will get all the data on the homepage feed.
GET https://tsn.com/team/:id which will get all the data for a specific team. returns 404 for error, and 200 code with { name, league, imageId, city, state, current_standings }
GET https://tsn.com/player/:id which will get all the data for a specific player. Returns 404 for error, 200 with { name, gender, age, team, league, image_url, height, weight, position }
GET https://tsn.com/live/:id which will get the initial data set for a specific game.
Sub wss://tsn.com/live for lets say https://tsn.com/:Id which will subscribe to a generic websocket connection on the page.
We could save the subscribers to a hash type subscribers {}, where the key is the gameid, and all the userIds are stored as the value.
From the server we do this on a new websocket connection for a game with "Id".
Then We simply publish these changes to all subscribers of 'Id'. For games we want live updates, so anything related to that game we can publish live..
There can be a large list of subscribers for this websocket connection. We can probably designate a microservice that just handles these connections and a background service per live event, that publishes to subscribers of that game every constantly. Pulling the most recent data from a nosql database.
So for storage we can use a sql database. So that data is consistent, If team A scores on team B we want Atomicity so there are no discrepancies between data in the game. ACID compliance is important here. We also want to make sure we shard this database so that we can scale.
We have a generic schema like this for each player but slightly different depending on the sport, as they will have different kinds of meta data. We can shard the database based on LeagueId so that the data we query for is relevant to us.
playerId INT Primary
fullname VARCHAR
gender
updated_at TIMESTAMP
position
age
height
weight
image_url
teamID
LeagueId
teamID INT Primary
team name
city
image_url
state
current_standings
LeagueId
We probably also need an S3 bucket for image resources related to teams and players. We can store this in one resolution as its not that important. Then we store the urls in our sql database.
We also have an LRU cache based system for most recently viewed teams/players etc.
By using a sql database we trade latency as we are heavy on read operations of data consistency. This means that our queries will take more time to read but the data.
We will have two different servers, one that handles regular tcp REST api and another that is just hosting our udp web socket service. This ensures that large volume users can not crash our regular server and separates concerns and load.
So we want to use a sql database to be acid compliant.
The sql database can be sharded based on LeagueId, so that we are not quering for irrelevant data. Our Redis cache is for our regular server and will use LRU so that the most recently viewed events load faster.
We also will establish a upd socket connection from the websocket server to the client. We will use this, as the data that is being updated is live, so we want to stream the data and any previously lost packets are not as important. Where as we use normal https tcp get requests on normal page load or when requesting data about teams/players regularly.
We are also using an s3 bucket for all of our images and then a pull based CDN for caching those resources.
The client talks to the load balancers for each respective server. These load balancers distribute the load for the websocket server which is handling live sporting events, and the regular server that is just meant for pulling in normal data for a team/player/game.
The regular server then uses a LRU write around cache, with a sql database when we get a cache miss. We sacrifice write operation latency for reads, as our users want to load data faster and most of our writes will happen internally to our sql database anyway.
We also have an s3 bucket for image resources and pull based CDN to cache those.
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
We us a sql database
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?