Design YouTube / Video Streaming
Uploads are slow and heavy, and views are huge and global. The interview is about the asynchronous transcoding pipeline and pushing nearly every byte of playback out to the CDN.
1 · Requirements
The Prompt
Design video upload, transcoding, and global streaming for 1B+ daily views.
Functional
- Upload large videos, resuming after a dropped connection
- Transcode each upload into several resolutions
- Stream with adaptive bitrate on any device
- Count views and show basic stats
Non-Functional
- Playback starts quickly and adapts to the viewer's bandwidth
- An upload is never lost once the client sees it complete
- The origin serves only a small share of video bytes
2 · Estimates
Drill This Phase First
Show the Answer and Estimates
Answer
About 50 TB a day
500,000 times 100 MB is 50 TB a day, or about 18 PB a year before transcoding multiplies it about 5x.
- Ingest
- 500,000 uploads a day at about 100 MB: 50 TB a day raw, about 18 PB a year before transcoding
- Renditions
- About 6 renditions from 240p to 4K multiply storage about 5x: roughly 250 TB a day after encoding
- Egress
- 1B views a day at about 10 MB streamed: 10 PB a day. The CDN absorbs over 95%, so the origin serves under 500 TB
- Streams
- About 35,000 stream starts a second at a 3x peak, with about 5M viewers watching at once
- Metadata
- About 1B videos at 2 KB each: roughly 2 TB in SQL, sharded by video_id
- Encoders
- Transcoding 50 TB a day takes about 30,000 vCPUs sustained, autoscaled on queue depth
3 · API
POST /uploads/init { filename, size, mime } → { upload_id, chunk_urls[] }
PUT /uploads/:id/chunks/:n (resumable) → 200
POST /uploads/:id/complete → { video_id, status: processing }
GET /videos/:id → { manifest_url, title, channel, stats }
GET /watch/:id/manifest.m3u8 → HLS playlist (signed, served by the CDN)
POST /videos/:id/view → 202 (async to counter pipeline)Data Model
videos (SQL, sharded by video_id):
video_id (PK) : uuid
uploader_id : uuid
title, desc : string
duration_s : int
status : enum(uploading|processing|ready|failed)
created_at : timestamp
renditions (SQL):
video_id (FK) : uuid
resolution : enum(240p|360p|...|2160p)
codec : string
s3_key : string
bitrate_kbps : int
view_counts (wide-column, partition = video_id, cluster = bucket_hour):
video_id : uuid
bucket_hour : timestamp
views : counter4 · High-Level Design
5 · Deep Dives
Resumable Uploads
Split the file into chunks, each with its own pre-signed URL, and track which chunks have landed. After a dropped connection the client asks for the missing chunk numbers and sends only those. Completion is one call that checks every chunk and queues the transcode job.
Transcoding Pipeline
Cut each video into segments a few seconds long and transcode them in parallel across workers, so a long upload finishes in minutes. A job names its video and rendition, and a retry overwrites the same output key, so a crashed worker leaves nothing half written.
Adaptive Bitrate and the CDN
HLS and DASH manifests list every rendition, and the player switches between them as bandwidth changes. Popular videos stay warm at the edge. Long-tail videos fall back to a regional cache and then the origin, which is where most of the remaining egress cost sits.
6 · Wrap Up
The Short Version
Upload to object storage, queue a job, have transcoder workers encode multiple bitrates, and serve them through a CDN. Metadata in SQL; view counts in wide-column. Adaptive bitrate (HLS/DASH).