Skip to content
SparkTime, home
System Design From Zero to Interview-Ready
Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
6 · Distributed Systems
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
11 · Large-Scale Case Studies
12 · Interview Readiness
Lesson 40 of 45

Lesson 40 · Large-Scale Case Studies

Design a Video Streaming Platform: Upload, Transcoding and Adaptive Streaming

Design an on-demand video platform: resumable uploads straight to object storage, a parallel transcoding pipeline that splits videos into chunks and renditions, adaptive bitrate streaming with HLS-style segments and manifests, CDN delivery at terabits per second, storage tiering, view counting, failures, content safety and the metrics that matter to viewers.

On this page

Key takeaways

  • Video platforms are dominated by bytes: storage grows by petabytes and viewing needs terabits per second, so object storage and CDNs carry the design.
  • Upload directly to object storage with resumable multipart uploads, then process asynchronously.
  • Transcode in parallel by splitting each video into chunks and renditions, orchestrated as a workflow with idempotent, retryable steps.
  • Adaptive bitrate streaming serves short segments at several qualities, so the player can switch as network conditions change; immutable segments cache extremely well.
  • Viewer experience is measured by start-up time and rebuffering, not server latency, and view counts are an eventually consistent analytics pipeline.

When you press play on a video, the first frame appears within a second or two, and if your train enters a tunnel the picture gets blurrier for a moment instead of freezing. Behind that are two large systems. One takes a creator's 4 GB upload over a patchy connection, turns it into dozens of versions at different qualities, and stores them. The other delivers small pieces of those versions to millions of viewers at once, from servers close to each of them.

An exercise in article 06 estimated that 50 million daily viewers watching 30 minutes each at 5 Mbps need roughly 10 terabits per second at peak; with a more realistic mix of qualities, this article arrives at about 8. This case study designs the platform that makes that possible. It is the first Level 3 case study: several pipelines, enormous byte volumes, and asynchronous processing everywhere.

What you will learn

#
  • How to estimate a byte-dominated system: ingest, storage, compute and egress.
  • Resumable uploads of very large files.
  • A parallel transcoding pipeline and how to orchestrate it reliably.
  • Adaptive bitrate streaming: renditions, segments and manifests.
  • CDN delivery, caching rules, access control and multi-CDN.
  • Storage tiering, view counting, failures and observability.

1. The problem

#

Build a video-on-demand platform where creators upload videos and viewers watch them on phones, laptops and TVs over networks ranging from fast fibre to weak mobile data. Videos must start quickly and keep playing smoothly as bandwidth changes.

2. Clarify the requirements

#

Question

Assumed answer

Impact

On-demand or live?

On-demand; live streaming is an extension

Batch processing is acceptable

Upload sizes?

Up to 10 GB, typically a few hundred MB

Multipart, resumable upload

Output qualities?

240p to 1080p (4K for some creators later)

Rendition ladder

Devices?

Mobile, web, smart TVs

Standard streaming formats

How soon after upload must a video be watchable?

Most videos within minutes; long videos within an hour

Parallel transcoding

Global audience?

Mostly India, some worldwide

CDN with good regional presence

Private or paid videos?

Some private and unlisted videos; paid content and DRM out of scope

Signed URLs

Comments, likes, recommendations?

Out of scope (other services)

Metadata only

View counts?

Shown publicly, can lag by minutes

Analytics pipeline

Functional requirements: upload a video; process it into streamable formats with thumbnails; stream with adaptive quality; show metadata and view counts; delete videos.

Non-functional requirements

Quality

Target

Playback start time

p90 under 2 seconds on a typical mobile connection

Smoothness

Rebuffering under 1% of watch time

Processing time

95% of videos under 20 minutes long are ready within 15 minutes of upload

Durability

An uploaded original is never lost

Availability

Playback 99.95%; uploads 99.9%

3. Assumptions and scale estimation

#

All figures below are assumptions for this exercise.

Uploads and ingest

Code
200,000 uploads/day; average raw size 300 MBIngest: 60 TB/day -> about 700 MB/s, about 5.6 Gbps on average

Stored renditions (a ladder of 5 qualities with assumed bitrates):

Code
240p 0.4 Mbps + 360p 0.8 + 480p 1.5 + 720p 3 + 1080p 6 = 11.7 Mbps for all renditions togetherAverage video 5 minutes = 300 s -> 11.7 x 300 / 8 = about 440 MB of renditions per video200,000 videos/day x 440 MB = about 88 TB/day of renditions; about 32 PB/yearPlus originals: 60 TB/day, about 22 PB/year (kept for re-processing; can move to archive storage)

Viewing and egress

Code
50 million DAU x 30 minutes/day; average delivered bitrate 2.5 Mbps (mix of qualities)Concurrent viewers on average = 50M x 30 / 1,440 minutes = about 1.04 millionAverage egress = 1.04M x 2.5 Mbps = about 2.6 Tbps; peak (factor 3) about 7.8 Tbps

Transcoding compute (an assumption to replace with measurements for your codec settings): producing the whole ladder takes about 10 CPU-minutes per minute of video.

Code
200,000 videos x 5 minutes x 10 CPU-minutes = 10 million CPU-minutes/day/ 1,440 minutes = about 6,900 CPU cores busy on average (more at peak upload times)

Conclusions: egress (terabits per second) and storage (tens of petabytes a year) dwarf everything else. The design must push delivery to CDNs, store bytes in object storage with tiering, and run transcoding as a large, elastic, parallel batch system. The metadata database is small by comparison.

4. API design

#
Code
POST /v1/videos{ "title": "Monsoon trek to Kudremukh", "size_bytes": 4200000000, "content_type": "video/mp4", "visibility": "public" }201 { "video_id": "v_9a1", "upload": { "upload_id": "...", "part_size": 104857600,       "part_urls_endpoint": "/v1/videos/v_9a1/upload-parts" } }POST /v1/videos/{videoId}/upload-parts {"part_numbers": [1,2,3]}  -> presigned URLs for those partsPOST /v1/videos/{videoId}/complete     {"parts": [...]}            -> 202 { "status": "processing" }GET  /v1/videos/{videoId}200 { "status": "ready", "duration_s": 312, "thumbnail_url": "...",      "playback_url": "https://cdn.example/v_9a1/master.m3u8?sig=..." , "views": 18234 }POST /v1/playback-events    (batched from players: start, quality switches, rebuffering, progress)DELETE /v1/videos/{videoId}

The upload API hands out presigned URLs per part, so bytes go straight to object storage (article 10); our servers handle only metadata. Playback URLs point to the CDN and are signed for private or unlisted videos.

5. Data model

#
Code
videos            (video_id PK, owner_id, title, description, visibility, status                   (uploading, processing, ready, failed, blocked, deleted), duration_s,                   original_key, renditions (list of quality and path), created_at, published_at)                   index (owner_id, created_at DESC)processing_jobs   (video_id, step, chunk, rendition, status, attempts, output_key, updated_at)                   PK (video_id, step, chunk, rendition)       -- one row per unit of workview_counts       (video_id, day, views)                         -- aggregated, eventually consistentObject storage layout (immutable objects, deterministic keys):  raw/v_9a1/original.mp4  work/v_9a1/chunks/00017.mp4  hls/v_9a1/1080p/segment_00017.ts      (or fragmented MP4 segments)  hls/v_9a1/1080p/index.m3u8  hls/v_9a1/master.m3u8  thumbs/v_9a1/0003.jpg

Deterministic object keys make processing steps idempotent: rerunning a step overwrites the same objects with identical content.

6. Baseline architecture

#
Code
Creator --upload--> App server (stores the file on disk) --> serves the MP4 file to viewers

A single file served from our servers: uploads tie up app servers, a 4 GB upload restarts from zero on any network drop, viewers on slow networks buffer constantly because there is only one quality, viewers far away wait on long round trips, and our servers would need to push terabits per second.

7. What breaks first?

#
  1. Uploads: large files through app servers, no resume.
  2. One quality for everyone: 1080p stalls on mobile data; 240p looks terrible on a TV.
  3. Transcoding time: encoding a long video sequentially into five qualities can take longer than the video itself.
  4. Egress: terabits per second cannot come from our origin.
  5. Storage growth: tens of petabytes a year.
  6. Popular videos: a viral video concentrates traffic on a few objects.

8. Scaling the design

#

Resumable upload

#

The client splits the file into parts (here 100 MB), uploads them in parallel to object storage with presigned URLs, retries only failed parts, and can resume after the app restarts by asking which parts are already present. Amazon's S3 documentation describes multipart upload for exactly this: parts uploaded independently and in any order, failed parts retransmitted without affecting others, pause and resume, and a recommendation to use it for objects of 100 MB or more (Multipart upload). On completion, the object store assembles the original, and an object-created event (or the client's complete call) starts processing.

The processing pipeline

#
Code
Upload complete  -> 1. Validate: real container and codec, duration, size limits; malware scan  -> 2. Probe: resolution, frame rate, audio tracks  -> 3. Split into chunks of about 10 seconds, at keyframe boundaries  -> 4. Transcode: for each chunk x each rendition, one task  (fan-out: a 5-minute video        = 30 chunks x 5 renditions = 150 parallel tasks)  -> 5. Assemble and package: per rendition, segment and write a media playlist; then the master playlist  -> 6. Thumbnails and preview sprites  -> 7. Moderation and copyright checks (automated, with human review for flagged items)  -> 8. Publish: write the master playlist last, set status = ready, emit VideoReady
  • Orchestration: a workflow engine or a saga orchestrator (article 21) tracks each video's steps in processing_jobs, schedules tasks onto queues, and retries failures. Each task is small (one chunk, one rendition), so failures cost little to redo.
  • Workers are a large, autoscaled fleet of competing consumers (article 11; Competing Consumers), scaled on queue depth, often on cheaper interruptible capacity since tasks are short and retryable.
  • Parallelism turns a 2-hour video's transcoding from hours into minutes, limited mainly by how many workers you can give it.
  • Priorities: short videos and verified creators can go to faster queues; very long uploads to a separate queue so they do not starve everyone else.
  • Idempotency: tasks write to deterministic keys; the orchestrator marks a task done only after its output exists; duplicates simply overwrite identical objects.
  • Re-processing: keeping originals lets you re-encode the library when a better codec arrives, as a background batch job.

Adaptive bitrate streaming

#

Instead of one file, each rendition is cut into segments a few seconds long, and playlists (manifests) describe them:

Code
master.m3u8                      lists the renditions and their bandwidths  240p/index.m3u8   -> segment_00001.ts, segment_00002.ts, ...  480p/index.m3u8   -> ...  1080p/index.m3u8  -> ...

The player downloads the master playlist, starts with a modest rendition (for a fast start), measures download speed as it fetches segments, and switches rendition at segment boundaries: up when bandwidth allows, down before its buffer runs out. HTTP Live Streaming (HLS), specified in RFC 8216, defines this playlist and segment format (RFC 8216, HTTP Live Streaming); MPEG-DASH is a widely used alternative built on the same idea. Because segments are ordinary files fetched over HTTP, any CDN can serve them.

Choices worth stating:

Choice

Trade-off

Segment length (for example 2 versus 6 seconds)

Shorter segments adapt faster and start sooner; more requests and slightly less efficient encoding

Number of renditions

More rungs give smoother adaptation; more storage and transcoding

Codecs

Newer codecs cut bitrate for the same quality; more encoding compute and device-support constraints

Delivery through CDNs

#
  • Segments and VOD playlists are immutable: give them long cache lifetimes (Cache-Control: public, max-age=31536000, immutable). A popular video's segments are served almost entirely from CDN edges after the first viewers in each area. A CDN such as CloudFront delivers content from edge locations close to viewers (What is Amazon CloudFront?).
  • An origin shield (a mid-tier cache between edges and object storage) collapses requests from many edges, so a viral video does not create thousands of origin fetches.
  • Pre-warm edges for scheduled premieres.
  • Changes use new paths (re-processed videos get a new version prefix) rather than invalidation; CloudFront's documentation recommends versioned file names over invalidation for frequently updated files (Invalidating files). Invalidation is kept for takedowns.
  • Multi-CDN: at terabits per second, many platforms use more than one CDN and steer traffic by cost and performance per region; a CDN outage then degrades, rather than stops, playback.

With 95% of bytes served from cache, origin egress at the 7.8 Tbps peak is about 390 Gbps, still large, which is why the shield and long TTLs matter so much.

Storage tiering

#

Viewing is highly skewed: most views go to recent and popular videos. Lifecycle rules move originals to archive storage after processing, and renditions of rarely watched videos to cheaper infrequent-access tiers (keeping the most-used renditions hot). Some platforms even delete the highest renditions of videos nobody watches and regenerate them on demand from the original.

View counting

#

Players send batched playback events (start, progress, quality changes, rebuffering) to an ingestion endpoint, which writes them to an event stream (article 11; Kafka-style streams keep events ordered per partition and retain them for replay (Introduction to Kafka)). Stream processors:

  • count a view when a session passes a threshold (for example 30 seconds or a percentage of the video), deduplicating by session and filtering obvious bots;
  • aggregate counts per video per minute and update view_counts, which the API serves from cache;
  • compute quality-of-experience metrics (start time, rebuffering) for monitoring.

The evolved architecture

#
Code
UPLOAD PATHCreator app --metadata--> Upload API --> metadata DB (status uploading)            --parts (presigned, parallel, resumable)--> Object storage (raw/)Object created --> Workflow orchestrator --> queues --> transcoding workers (autoscaled)             --> packaging --> object storage (hls/) --> moderation --> publish (status ready, VideoReady event)PLAYBACK PATHViewer app --> Metadata API (cached) --> signed playback URL           --> CDN edges (multi-CDN) --> origin shield --> object storage (hls/)Player events --> ingestion --> stream --> view counts, QoE metrics

9. Failure scenarios and reliability

#

Failure

Effect

Response

Upload interrupted

Partial upload

Resume by retrying missing parts; lifecycle rule cleans abandoned uploads

Transcoding worker dies mid-task

Task unfinished

Queue redelivers; deterministic outputs make reruns safe

A video fails repeatedly (corrupt file)

Poison task

Limited retries, then dead letter; video marked failed, creator notified

Orchestrator restarts

Workflow paused

State in processing_jobs; resumes from the last completed step

CDN outage in a region

Playback errors

Steer to another CDN; players retry other hosts

Viral video

Origin requests surge

Origin shield, long TTLs, pre-warming

Corrupted segment in storage

Playback glitch

Checksums verified at packaging; re-package from the original

Object storage regional outage

Playback and uploads fail in that region

Cross-region replication of popular renditions and originals per requirements (article 24)

10. Consistency

#
  • Publishing is atomic from the viewer's point of view: the master playlist is written last and the status switches to ready only after every rendition exists, so no viewer ever loads a playlist that references missing segments.
  • Metadata, search and counts are eventually consistent (seconds to minutes).
  • Deletion: metadata status changes immediately (the video stops being playable through the API, and signed URLs stop being issued), CDN caches are invalidated for takedowns, and objects are deleted asynchronously.
  • Creators see their own video's processing status immediately (read from the primary).

11. Security

#
  • Upload safety: validate formats by content, not file extension; scan for malware; enforce size and duration limits; rate-limit uploads per account.
  • Content safety: automated moderation and copyright matching before publishing, human review for flagged videos, and fast takedown.
  • Access control: private and unlisted videos use short-lived signed URLs or signed cookies at the CDN, and the bucket accepts requests only from the CDN.
  • Hotlinking and scraping: signed URLs with expiry; rate limits on metadata APIs.
  • Paid content (extension): digital rights management encrypts segments and controls key delivery; it adds licence servers and device constraints.

12. Observability

#

Signal

Why

Video start time (time to first frame), p50 and p90, by region and network

The viewer's first impression

Rebuffering ratio and average delivered bitrate

Smoothness and quality

Playback error rate by CDN, region and device

Delivery health; multi-CDN steering

CDN hit ratio and origin egress

Cost and origin protection

Upload success rate and resume rate

Creator experience

Processing time (upload complete to ready), p95; queue depth per stage

Pipeline health

Transcoding failures and dead letters

Bad inputs or bugs

View-count pipeline lag

Freshness of counts

The most important observation: the metrics that matter here are measured on the client (start time, rebuffering), because server latency says little about the viewer's experience.

13. Trade-offs

#

Decision

Chosen

Alternative

Why

Upload

Direct multipart to object storage

Through app servers

Scales, resumable, keeps servers out of the byte path

Transcoding

Chunked and parallel

Whole-file sequential

Minutes instead of hours; small retryable tasks

Renditions

Full ladder for new videos; regenerate rare ones on demand

Everything always

Storage cost versus readiness

Streaming

Adaptive bitrate with short segments

Single progressive file

Smooth playback on changing networks

Delivery

Multi-CDN with origin shield

Single CDN or own servers

Terabit egress, resilience, cost leverage

Storage

Tiered by age and popularity

Single hot tier

Tens of petabytes per year

14. The final interview answer

#

"This is a byte-dominated system: about 60 TB of uploads a day, around 90 TB of renditions a day, and roughly 8 Tbps of viewing traffic at peak.

Creators upload directly to object storage with resumable multipart uploads; the API only handles metadata. Completion starts a workflow: validate and scan, split the video into 10-second chunks at keyframes, transcode every chunk into five renditions in parallel on an autoscaled worker fleet, package HLS segments and playlists, generate thumbnails, run moderation, and publish by writing the master playlist last and marking the video ready. Every task writes to deterministic keys, so retries are safe.

Viewers get a signed playback URL; the player fetches the master playlist from a CDN and adapts quality segment by segment. Segments are immutable and cached with very long lifetimes behind an origin shield, across more than one CDN, so the origin sees a few percent of bytes. Storage is tiered by age and popularity. Playback events stream into an analytics pipeline that counts views after a threshold and measures start time and rebuffering, which are the metrics we actually optimise."

Exercises

#

Exercise 1

Storage for a 4K tier

#

You add a 4K rendition at 16 Mbps for 20% of new videos. Using the assumptions above (200,000 videos a day, 5 minutes each), how much extra storage per day and per year does it add?

Exercise 2: How long for a 2-hour video?

#

A 2-hour video is split into 10-second chunks and transcoded into 5 renditions. Each chunk-rendition task takes about 60 seconds of wall time on one worker (an assumption). How many tasks are there, how long would it take on one worker, and how long with 300 workers available for this video? What else limits the total time?

Exercise 3: Segment length

#

A product manager asks for 1-second segments "so playback starts faster". What are the costs, and what would you recommend?

Exercise 4: Honest view counts

#

Design view counting that resists inflation by bots, while keeping counts within a few minutes of real time. What counts as a view, and where do you deduplicate?

Show solutionHide solution
Code
Per 4K video: 16 Mbps x 300 s / 8 = 600 MBVideos per day with 4K: 20% of 200,000 = 40,000Extra per day: 40,000 x 600 MB = 24 TB; per year: about 8.8 PB

A 4K rung for only a fifth of videos adds about 27% to the daily rendition storage (24 TB on top of 88 TB). Good candidates for tiering: generate 4K only for videos from creators who upload in 4K and whose viewers have 4K devices, and move 4K renditions of unpopular videos to cold storage or delete and regenerate them on demand.

Exercise 2

Show solutionHide solution
Code
Chunks: 7,200 s / 10 s = 720Tasks: 720 x 5 renditions = 3,600One worker: 3,600 x 60 s = 216,000 s = 60 hours300 workers: 3,600 / 300 = 12 rounds x 60 s = about 12 minutes

Other limits: downloading the original and uploading outputs (network bandwidth to object storage); the splitting and packaging steps (partly sequential, though packaging can run per rendition in parallel); queue scheduling overhead; fairness (one huge video should not grab all workers, so per-video concurrency caps apply, which lengthens its time but protects others); and moderation, which may need human review.

Exercise 3

Show solutionHide solution

Costs of 1-second segments: many more requests (6 times as many as 6-second segments: more load on CDNs and origin, more per-request overhead, worse on high-latency mobile links); less efficient compression (keyframes at every segment start increase bitrate for the same quality); more objects and playlist entries.

Start-up time depends mostly on fetching the playlist, the first segment at a modest rendition and buffering a few seconds. Better levers: start at a lower rendition and switch up; a short first segment or a small "fast start" rendition; preloading the playlist when the user hovers or scrolls to the video; and good CDN hit ratios. A segment length of 2 to 4 seconds is a common compromise; measure start time and rebuffering with experiments before deciding.

Exercise 4

Show solutionHide solution
  • Definition: a view is a playback session that plays at least N seconds (for example 30) or a percentage of a short video, from a session that passes basic validity checks (signed playback token, real progress events, plausible timing).
  • Deduplication: count at most one view per (user or device, video) per time window (for example 30 minutes), in the stream processor, using keyed state with expiry.
  • Bot filtering: discard sessions without valid tokens, with impossible behaviour (thousands of starts from one IP, no progress events, headless patterns), and from known bad sources; weight or hold back views from new accounts and suspicious traffic for later validation.
  • Freshness: the stream processor emits per-minute aggregates; the API serves a cached count. Optionally show a provisional count quickly and adjust it after a delayed fraud review (some platforms visibly freeze or adjust counts while validating).
  • Audit: keep raw events for a period so counts can be recomputed if the rules change.

Where to go next

#

Sources & further reading

  1. docs.aws.amazon.com
  2. rfc-editor.org
  3. docs.aws.amazon.com
  4. docs.aws.amazon.com
  5. learn.microsoft.com
  6. kafka.apache.org
  • Guide · Technology

    Start Here: Your Roadmap from Zero to Job-Ready DSA

  • Guide · Technology

    Heaps and Priority Queues

  • Guide · Career

    A LinkedIn Profile That Gets Recruiter Messages