We need a way for users to see a specific video
We need a way for users to upload a video
We want to prioritize latency and availability of the system.
Estimate the scale of the system you are going to design...
Imagine there are 100 million active users on youtube a month, let say each of them watches about 10 videos a week or 40 videos a month. That is a total of 4 billion read requests a month. We can negate how many write requests as this probably doesn't happen as often.
But in terms of database lets say there are 2 million videos uploaded monthly, With each video being around 1gb of data, thats roughly 2 petabytes of storage on something like S3 we need monthly. And assuming 2 million requests each have some meta data about the video, we can say each request will have 1kb of meta data so roughly 2 gigabytes of database storage monthly.
For creating a new video we can have a post request to https://youtube.com/create_video. We will give userid, title, description, the actual raw video data. We will return a 302 code when the upload begins, and a 400 code if the upload fails. At this point we establish a websocket connection with the server that sends us a notification when the video finishes uploading.
For seeing a video we can have a get request https://youtube.com/:id. Here we will use the video id parameter which will normally be encoded to prevent sql injection attacks with that video id on the server. We will get a 200 code that gives us the video url, in which case then the client will request this video from a cdn. Or we return a 404 error for invalid links or videos that have not been found on our server.
we will use a no sql database because this will be a read heavy use case. We can also denormalize any data as we scale so that we make sure not to make additional queries and lower our latency. For storage we are using something like Amazon S3 to store the video files.
So we have a load balancer to distribute the load to the server. We use a LRU redis cache, and a nosql database which will hold the file url. We then have an s3 bucket to hold the raw data of the videos. We also have a file compresser that then takes the raw files and compresses them then storing them in different resolution formats 256, 512 etc stored into a our S3 and a second nosql database. We also have a background service worker that takes the files from this second database and updates our content data networks periodically.
Client talks to load balancer.
Get video: load balancer distributes load to server
server responds to client with a 404, invalid url if the resource doesn't exist otherwise it checks redis cache. If cache miss, it hits the no sql database for the resource. It gets the url of the video which is then sent back to the client. with a 200 status. From there the client hits the content delivery network with the url it has to then load the video.
Upload video: load balancer distributes load to server.
server responds to client with a 404, if the video is too large or missing metadata such as title and description. Otherwise Server responds to the client with a 301 code that the upload has begon. It then uploads the raw video data to s3 bucket. Then updating the nosql database with the url of the video and also writing to redis LRU cache.
We then have a background file compressor which periodically takes files out of the s3 bucket and compresses them for different resolutions. It then loads them into a seperate nosql database.
We also have a second background worker as well that takes these videos from the nosql database periodically and loads them into our cdn networks in the world.
We want to replicate load balancers and servers to reduce SPOF here.
We also want to scale our horizontal database using sharding to reduce latency.
The File compressor can use codec to compress the raw files in the background before loading them into a seperate nosql database, and then deleting the raw video file. Assuming there are around 2 millions videos uploaded monthly so about 20 per second, and each upload roughly takes 1 minute, we would need roughly 1200 service workers to take care of this load.
We also have a second background service worker that fetches videos from our second sql database and loads them into our cdns in the world. This can run more periodically so like very 5 minutes? and the latency is not as important.
We can denormalize data in our first nosql database to container user information, for example when a video is loaded we want to see information about the upload of the video etc.
We use a LRU write around cache based system so we trade write latency for read latency. As its more important for videos to load faster vs when uploading them.
We are using a nosql database and using sharding which trades consistency for latency here. It is more important here that videos load faster even if they are not available instantly as we upload them to all our databases.
We use service workers that compress and distribute files to our cdns periodically so again, it may mean a video is available in one part of the world vs another.
Do to the async nature of this design and lack of data consistency, a video being uploaded by a famous Youtuber may not be available in all parts of the world instantly.
We also have many single point of failures in this system.
When users request a feed of a videos, to only upload those that are available in that cdn's region. So maybe we can update some metadata about which videos are available where so a user can only see videos that are available to them. We could also look at implementing a message queue so that a video is only available after uploading it once our background workers have distributed it to relevant cdns. So this is a message queue an uploader subs to when uploading, they get a 301 code initially to indicate the video is uploading and afterwards a notification that it is complete. Now when this video is shared, it is available everywhere.
We need multiple copies of our S3 bucket, and our databases in case this system fails. Also multiple background service workers to ensure that videos reach our cdns if one fails.