Netflix system design

Nút Play đi tới AWS. Video thì không.The Play button goes to AWS. The video doesn’t.

Một cú bấm mở ra hai đường đi tách biệt: một yêu cầu nhỏ tới cloud để ra quyết định, và một luồng byte dài từ chiếc máy đặt trong hoặc gần mạng nhà mạng của bạn.One tap opens two separate paths: a small request to the cloud that makes decisions, and a long stream of bytes from a box inside or near your ISP’s network.

Control plane and data plane / Mặt phẳng điều khiển và mặt phẳng dữ liệu AWS Zuul, Playback API, EVCache, Cassandra… vài KB, ra quyết định a few KB of decisions Open Connect OCA trong ISP hoặc tại IXP OCA in your ISP or at an IXP FreeBSD + NGINX FreeBSD + NGINX hàng GB mỗi phiên xem gigabytes per session Bạn bấm Play You press play hỏi một lần asked once luồng byte liên tục continuous byte stream
Nét đứt: quyết định lúc chạyDashed: runtime decision Nét dày: byte videoThick: video bytes

Chọn cái nàoWhich one do you need

Câu hỏi đầu tiên không phải “dùng gì”, mà là “có cần dùng gì không”.The first question isn’t “which one”, it’s “do I need any of them”.

Baseline: không dùng gì cảBaseline: use none of it

Nếu bạn có dưới vài trăm nghìn người dùng, dưới vài nghìn request mỗi giây, và băng thông chưa phải chi phí lớn nhất: một monolith, PostgreSQL (kèm full-text search), một CDN thương mại và một dịch vụ video có sẵn như Mux, Cloudflare Stream hay AWS MediaConvert là đủ. Netflix trả giá cho từng thành phần vì họ chiếm một phần lớn traffic internet. Bạn gần như chắc chắn chưa ở đó.

If you have fewer than a few hundred thousand users, fewer than a few thousand requests per second, and bandwidth isn’t your biggest cost: a monolith, PostgreSQL (with full-text search), a commercial CDN and a managed video service such as Mux, Cloudflare Stream or AWS MediaConvert are enough. Netflix pays for each component because it carries a large share of internet traffic. You almost certainly don’t.

Mang về ngay hôm nay, ở mọi quy mô: tách quyết định khỏi giao hàng. App trả về signed URL, file lớn đi thẳng từ CDN tới người dùng.Take this home today, at any scale: separate deciding from delivering. Your app returns a signed URL; large files go straight from the CDN to the user.

Có giao file lớn (video, bản cập nhật, ảnh gốc)?
├─ Không → xuống phần backend
└─ Có → file có đi qua app server?
        ├─ Có → sửa ngay: trả signed URL, để CDN giao
        └─ Không → egress là chi phí số 1 VÀ bạn chiếm phần lớn traffic của nhiều ISP?
                   ├─ Không → CDN thương mại. Dừng.
                   └─ Có → cân nhắc đặt máy trong ISP (Open Connect)

Mỗi video được xem bao nhiêu lần?
├─ Vài chục → dịch vụ video có sẵn, ladder mặc định
└─ Rất nhiều → ladder theo nội dung → tối ưu theo cảnh khi băng thông đắt hơn compute

Backend
├─ Hơn 3 service, nhiều loại client?                → API gateway (kiểu Zuul)
├─ Đọc chậm, đọc/ghi > 10:1, đã tối ưu truy vấn?    → cache (kiểu EVCache)
├─ Ghi khổng lồ, truy vấn biết trước, sống qua mất region? → Cassandra; còn lại → PostgreSQL
├─ Một sự kiện, nhiều bên nghe?                     → Kafka; ít bên → gọi thẳng hoặc outbox
├─ Tìm văn bản chậm trên hơn vài triệu bản ghi?    → search engine
└─ Người dùng thoát vì không tìm được gì để xem?   → recommendations, bắt đầu bằng luật đơn giản
Do you deliver large files (video, updates, original images)?
├─ No → go to the backend questions
└─ Yes → do files pass through your app server?
        ├─ Yes → fix it now: return a signed URL, let the CDN deliver
        └─ No → is egress your #1 cost AND do you carry a big share of many ISPs’ traffic?
                   ├─ No → commercial CDN. Stop.
                   └─ Yes → consider boxes inside ISPs (Open Connect)

How many times is each video watched?
├─ Dozens → managed video service, default ladder
└─ Very many → content-aware ladder → per-shot when bandwidth costs more than compute

Backend
├─ More than 3 services, many client types?           → API gateway (Zuul-style)
├─ Slow reads, read/write > 10:1, queries optimized?  → cache (EVCache-style)
├─ Massive writes, known queries, survive region loss? → Cassandra; otherwise → PostgreSQL
├─ One event, many listeners?                         → Kafka; few → direct call or outbox
├─ Text search slow on more than a few million rows?  → search engine
└─ Users leave because they can’t find anything?      → recommendations, start with simple rules

Một cú bấm, năm bướcOne tap, five steps

Màu số cho biết bước đó chạy ở mặt phẳng nào. Từ bước 3, video không chạm vào AWS.The number color shows which plane the step runs on. From step 3 on, video never touches AWS.

  1. App gửi yêu cầu phát qua load balancer tới Zuul.The app sends a play request through the load balancer to Zuul.Control plane
  2. Playback API kiểm tra quyền, cấp license DRM, lọc stream hợp thiết bị, nhờ Steering xếp hạng OCA rồi trả manifest.The Playback API checks entitlement, issues DRM, filters streams for the device, asks Steering to rank OCAs and returns a manifest.Control plane
  3. Thiết bị tự kết nối OCA và tải từng đoạn video qua HTTPS.The device connects to an OCA itself and fetches video segments over HTTPS.Data plane
  4. Player đổi nấc chất lượng mỗi vài giây theo băng thông thực tế.The player switches quality rungs every few seconds based on real bandwidth.Data plane
  5. Suốt phiên xem, sự kiện phát chảy về AWS qua Kafka/Keystone để đo chất lượng và cá nhân hoá.Throughout the session, playback events flow back to AWS via Kafka/Keystone for quality metrics and personalization.Control plane

Tra cứu từng thành phầnComponent reference

Mỗi thẻ: tóm tắt, câu đánh đổi, sơ đồ, dùng cho, được, mất, và dấu hiệu nhận biết bạn cần nó.Each card: summary, trade-off, diagram, use for, gain, lose, and the tell that you need it.

Cửa ngõEdge

Zuul

Cửa ngõEdge

API gateway tầng 7 của Netflix. Mọi request từ thiết bị đều đi qua chuỗi filter của nó trước khi tới service.Netflix’s layer-7 API gateway. Every device request passes through its filter chain before reaching a service.

Đánh đổiTrade-offĐổi thêm một hop và một điểm lỗi tập trung lấy một chỗ duy nhất kiểm soát mọi traffic.Trades an extra hop and a central point of failure for one place to control all traffic.

device → ELB → Zuul ─┬→ Playback API
                     ├→ Recommendations
                     └→ Search
 [inbound] → [endpoint] → [outbound]
Dùng choUse for
Auth, rate limit, canary, cắt tải, chuyển region.Auth, rate limiting, canary, load shedding, region failover.
ĐượcGain
Client không cần biết topology; failover chỉ bằng đổi route.Clients don’t know topology; failover is just a route change.
MấtLose
Gateway sập là tất cả sập; dễ thành monolith thứ hai.Gateway down means everything down; easily becomes a second monolith.

Dấu hiệu:Tell: app phải biết địa chỉ của hơn ba service.the app has to know more than three service addresses.

Dịch vụ điều khiểnControl services

Playback API

Điều khiểnControl

Nhận “tôi muốn xem X”, trả về manifest: stream hợp thiết bị, license DRM, danh sách OCA đã xếp hạng.Takes “I want to watch X” and returns a manifest: device-compatible streams, a DRM license, a ranked list of OCAs.

Đánh đổiTrade-offĐổi một service nằm trên đường găng lấy quyền điều khiển việc giao hàng mà không chạm vào byte nào.Trades a service on the critical path for control over delivery without touching a byte.

play(title, caps)
  → entitled? → DRM → streams
  → Steering(IP, BGP, health)
  ← [1080p AV1 @ OCA-a, OCA-b]
Dùng choUse for
Giao file lớn có kiểm soát quyền, DRM, chọn giữa nhiều CDN.Access-controlled large files, DRM, choosing among CDNs.
ĐượcGain
AWS chỉ xử lý vài KB mỗi lượt play; đổi chiến lược không cần cập nhật app.AWS handles a few KB per play; strategy changes need no app update.
MấtLose
Nó sập thì không ai bấm play được, dù OCA vẫn sống.If it’s down nobody can press play, even with every OCA healthy.

Dấu hiệu:Tell: bạn đang tạo signed URL cho file trên S3.you’re generating signed URLs for files on S3.

Recommendations

Điều khiểnControl

Homepage là các hàng, không phải một danh sách. Hệ thống chọn hàng nào, thứ tự hàng, title trong hàng và cả ảnh bìa.The homepage is rows, not one list. The system picks which rows, their order, the titles in each and even the artwork.

Đánh đổiTrade-offĐổi một pipeline ML nặng nề phải vận hành lấy việc người dùng tìm thấy thứ để xem mà không phải đi tìm.Trades a heavy ML pipeline to run for users finding something to watch without searching.

offline (train) → nearline (events)
              → online (assemble, cache)
[Continue] [Because X] [Top 10] ...
Dùng choUse for
Catalog lớn hơn khả năng duyệt: phim, nhạc, thương mại điện tử.Catalogs bigger than anyone can browse: video, music, e-commerce.
ĐượcGain
Khoảng 80% giờ xem Netflix đến từ đề xuất (Gomez-Uribe & Hunt, 2015).About 80% of Netflix hours come from recommendations (Gomez-Uribe & Hunt, 2015).
MấtLose
Cold start, vòng lặp phản hồi, chỉ số offline không khớp online.Cold start, feedback loops, offline metrics that don’t match online.

Dấu hiệu:Tell: người dùng thoát vì “không có gì để xem”.users leave because “there’s nothing to watch”.

Trạng thái và sự kiệnState and events

EVCache

Trạng tháiState

Cache phân tán trên memcached, với client tự sao chép dữ liệu qua mọi zone và giữa các region.Distributed cache on memcached, with a client that replicates across every zone and between regions.

Đánh đổiTrade-offĐổi tính nhất quán và tiền RAM lấy độ trễ dưới mili-giây.Trades consistency and RAM spend for sub-millisecond latency.

write → zone A, B, C
read  → local zone
      → miss: other zone → DB
Dùng choUse for
Homepage tính sẵn, session, feature flag, chắn DB khi tăng đột biến.Precomputed homepages, sessions, feature flags, shielding the DB from spikes.
ĐượcGain
Mất một zone vẫn còn bản sao; region dự phòng có cache ấm.Losing a zone leaves copies; the standby region has a warm cache.
MấtLose
Không phải nguồn sự thật; cache lạnh dồn hết tải xuống DB.Not a source of truth; a cold cache dumps all load on the DB.

Dấu hiệu:Tell: tỷ lệ đọc/ghi trên 10:1 và truy vấn đã tối ưu.read/write above 10:1 with queries already optimized.

Cassandra

Trạng tháiState

Database wide-column không có leader. Mọi node ngang hàng, nhận cả đọc lẫn ghi, ở nhiều region cùng lúc.A leaderless wide-column database. Every node is equal and takes reads and writes, in several regions at once.

Đánh đổiTrade-offĐổi sự linh hoạt truy vấn và nhất quán mạnh lấy khả năng ghi không bao giờ dừng.Trades query flexibility and strong consistency for writes that never stop.

  N1 ─ N2      key → N3,N4,N5 (RF=3)
 N6     N3     QUORUM = 2 of 3
  N5 ─ N4      region A ⇄ region B
Dùng choUse for
Lịch sử xem, chuỗi thời gian, dữ liệu ghi nhiều với truy vấn biết trước.Viewing history, time series, write-heavy data with known queries.
ĐượcGain
Không có điểm chết đơn lẻ; mở rộng gần tuyến tính.No single point of failure; near-linear scaling.
MấtLose
Không join, không transaction; truy vấn mới thường là bảng mới.No joins, no transactions; a new query usually means a new table.

Dấu hiệu:Tell: bạn liệt kê được mọi truy vấn trên một trang giấy, và không được phép dừng ghi.you can list every query on one page, and writes may never stop.

Kafka / Keystone

Sự kiệnEvents

Log sự kiện append-only. Keystone là pipeline của Netflix trên Kafka, xử lý luồng bằng Flink.An append-only event log. Keystone is Netflix’s pipeline on Kafka, with stream processing on Flink.

Đánh đổiTrade-offĐổi phản hồi tức thời và sự đơn giản lấy việc bên ghi không cần biết ai đang đọc.Trades immediate replies and simplicity for writers that don’t need to know who reads.

apps → Kafka → Flink ─┬→ S3 warehouse
                      ├→ Elasticsearch
                      └→ real-time
Dùng choUse for
Một sự kiện nhiều bên nghe, phân tích thời gian thực, đệm tải.One event with many listeners, real-time analytics, buffering.
ĐượcGain
Đọc lại được; thông lượng cỡ hàng nghìn tỷ sự kiện mỗi ngày.Replayable; throughput on the order of trillions of events a day.
MấtLose
Không có hỏi–đáp đồng bộ; thứ tự chỉ trong một partition.No synchronous request–reply; ordering only within a partition.

Dấu hiệu:Tell: service A gọi đồng bộ B, C, D chỉ để báo tin.service A calls B, C and D synchronously just to notify them.

Pipeline media (offline, vẫn chạy trên AWS)Media pipeline (offline, still on AWS)

Mezzanine

Media

File master chất lượng rất cao từ studio, thường là gói IMF. Nguồn duy nhất cho mọi bản encode.The very high quality studio master, often an IMF package. The single source for every encode.

Đánh đổiTrade-offĐổi chi phí lưu trữ khổng lồ lấy khả năng tạo lại mọi bản phân phối trong tương lai.Trades enormous storage cost for recreating every distribution version in the future.

studio → mezzanine (GB … TB)
       → QC → archive → encoder
new codec? re-encode from here
Dùng choUse for
Mọi pipeline media; lưu ảnh gốc; tài liệu nguồn sinh nhiều định dạng.Any media pipeline; original photos; source docs that yield many formats.
ĐượcGain
Encode lại cho AV1 mà không mất chất lượng tích luỹ.Re-encode for AV1 without compounding quality loss.
MấtLose
Rất nặng; nhận và kiểm tra chậm trước ngày ra mắt.Very heavy; slow ingest and QC before launch.

Dấu hiệu:Tell: bạn từng nén lại một file đã nén và thấy hình vỡ.you once recompressed a compressed file and saw artifacts.

Encoder

Media

Tối ưu theo từng cảnh quay, không theo cả bộ phim. Cảnh tĩnh ít bit, cảnh hành động nhiều bit, chấm điểm bằng VMAF.Optimized per shot, not per title. Static shots get few bits, action gets many, scored with VMAF.

Đánh đổiTrade-offĐổi chi phí compute trả một lần lấy băng thông tiết kiệm trên mọi lượt xem.Trades compute paid once for bandwidth saved on every view.

mezzanine → split by shot
  → encode ∥ on EC2 → VMAF
  → best mix per bitrate → stitch
Dùng choUse for
Thư viện xem nhiều lần, mạng di động yếu, nội dung đa dạng.Heavily watched libraries, weak mobile networks, varied content.
ĐượcGain
Cùng chất lượng, ít bit hơn; riêng tối ưu theo title đã tiết kiệm khoảng 20%.Same quality, fewer bits; per-title alone saved about 20%.
MấtLose
Compute rất lớn; quá chậm cho live.Huge compute; too slow for live.

Dấu hiệu:Tell: hoá đơn băng thông lớn hơn hoá đơn compute.your bandwidth bill is bigger than your compute bill.

Bitrate ladder

Media

Các nấc (độ phân giải, bitrate, codec) cho mỗi title. AVC vẫn phổ biến nhất, AV1 khoảng 30% giờ xem (12/2025), HEVC cho 4K/HDR.Rungs (resolution, bitrate, codec) per title. AVC is still most used, AV1 about 30% of viewing (Dec 2025), HEVC for 4K/HDR.

Đánh đổiTrade-offĐổi dung lượng lưu trữ nhân lên lấy việc mỗi thiết bị nhận đúng thứ nó chơi được ngay lúc đó.Trades multiplied storage for every device getting exactly what it can play right then.

 4K    AV1 / HEVC
1080p  AV1 / HEVC / AVC
 480p  AVC
 240p  AVC  ← never stall
Dùng choUse for
Mọi streaming qua mạng không ổn định; ảnh responsive (srcset).Any streaming over unstable networks; responsive images (srcset).
ĐượcGain
AV1 dùng ít hơn khoảng 1/3 băng thông, ít buffering hơn 45% (Netflix).AV1 uses about a third less bandwidth, 45% fewer rebuffers (Netflix).
MấtLose
Số file nhân theo nấc × codec × tập; phải giữ AVC rất lâu.Files multiply by rungs × codecs × episodes; AVC must be kept for years.

Dấu hiệu:Tell: bạn hỗ trợ cả TV mười năm tuổi lẫn điện thoại đời mới.you support ten-year-old TVs and brand new phones.

Giao hàng (data plane)Delivery (data plane)

Open Connect

Giao hàngDelivery

CDN riêng của Netflix, phục vụ 100% video. Hơn 18.000 OCA ở 175 quốc gia (2024), đặt tại IXP và miễn phí trong mạng ISP.Netflix’s own CDN, serving 100% of video. 18,000+ OCAs in 175 countries (2024), at IXPs and free inside ISP networks.

Đánh đổiTrade-offĐổi vốn phần cứng và hàng nghìn quan hệ với nhà mạng lấy việc không phải trả tiền cho từng byte đi ra.Trades hardware capital and thousands of ISP relationships for not paying for every byte out.

night: pre-fill predicted titles
OCA in ISP ───────────→ home (preferred)
OCA at IXP → peering → ISP → home
storage 2U ≤360 TB HDD · flash 2U 24 TB
Dùng choUse for
Chỉ khi bạn chiếm phần đáng kể traffic internet với nội dung dự đoán được.Only when you carry a real share of internet traffic with predictable content.
ĐượcGain
Gần 95% traffic đi qua kết nối trực tiếp với ISP, gần như không qua transit.Close to 95% of traffic over direct ISP connections, almost no transit.
MấtLose
Chỉ hợp lý ở quy mô khổng lồ; logistics phần cứng toàn cầu.Only sensible at enormous scale; global hardware logistics.

Dấu hiệu:Tell: hoá đơn egress CDN là dòng chi phí lớn nhất của công ty.CDN egress is the company’s single biggest cost line.

Bảng đánh đổiTrade-off table

Thứ nằm trên đường găng phải đơn giản và dư thừa. Thứ không nằm trên đó được phép phức tạp, vì nó chết thì trải nghiệm chỉ giảm chứ không mất.Whatever is on the critical path must be simple and redundant. Whatever isn’t may be complex, because when it fails the experience degrades instead of disappearing.

Thành phầnChạy lúc nàoTrên đường găng của Play?Chi phí chínhĐộ khó vận hànhNếu nó chết
ZuulMỗi requestCóComputeTrung bìnhKhông gì chạy được
Playback APIMỗi lượt playCóComputeTrung bìnhKhông ai bấm play được
RecommendationsOffline + onlineKhôngCompute ML, dữ liệuCaoHiện trang dự phòng
SearchMỗi truy vấnKhôngCompute, RAMTrung bìnhMất tìm kiếm, vẫn xem được
EVCacheMỗi lượt đọcGián tiếpRAMTrung bìnhDB bị dồn tải, chậm dây chuyền
CassandraMỗi lượt ghi trạng tháiGián tiếpĐĩa, nodeCaoMất lịch sử, tiến độ xem
Kafka / KeystoneGần thời gian thựcKhôngĐĩa, mạngCaoMất số liệu, xem vẫn chạy
MezzanineMột lần mỗi titleKhôngLưu trữThấpKhông encode lại được
EncoderOfflineKhôngCompute rất lớnCaoTitle mới không ra mắt được
Bitrate ladderThiết kế offline, chọn lúc chạyCó (ở player)Lưu trữThấpDừng hình, chất lượng kém
Open ConnectMỗi giây xemCóPhần cứng, quan hệ ISPRất caoChuyển sang OCA khác hoặc IXP
ComponentWhen it runsOn the Play critical path?Main costOps difficultyIf it dies
ZuulEvery requestYesComputeMediumNothing works
Playback APIEvery playYesComputeMediumNobody can press play
RecommendationsOffline + onlineNoML compute, dataHighFallback page shown
SearchEvery queryNoCompute, RAMMediumSearch lost, viewing works
EVCacheEvery readIndirectlyRAMMediumDB overloaded, cascading slowness
CassandraEvery state writeIndirectlyDisk, nodesHighHistory and progress lost
Kafka / KeystoneNear real timeNoDisk, networkHighMetrics lost, viewing works
MezzanineOnce per titleNoStorageLowCan’t re-encode
EncoderOfflineNoVery large computeHighNew titles can’t launch
Bitrate ladderDesigned offline, picked at runtimeYes (in the player)StorageLowStalls, poor quality
Open ConnectEvery second of viewingYesHardware, ISP relationshipsVery highFail over to another OCA or IXP

Anti-patterns

Sai lầmVì sao saiSửa thế nào
Vẽ hệ thống video như một pipeline duy nhấtGộp hai loại tải chênh nhau hàng triệu lần vào một chỗTách control plane và data plane ngay trên sơ đồ
Cho file video đi qua app serverApp server thành ống dẫn băng thông, đắt và nghẽnTrả signed URL, để CDN giao trực tiếp
Tự xây CDN vì “Netflix làm thế”Lợi thế đến từ quy mô và quan hệ ISP, không từ phần mềmDùng CDN thương mại tới khi egress là chi phí số một
Chọn Cassandra vì nghe nói mở rộng tốtMất join, transaction, phải biết trước mọi truy vấnPostgreSQL trước, đo, rồi mới tách phần ghi nặng
Coi cache là nơi lưu dữ liệuCache bị xoá hoặc khởi động lại là mấtDB là nguồn sự thật, mọi key có TTL
Nhồi logic nghiệp vụ vào gatewayThành monolith thứ hai, nằm trên mọi requestGateway chỉ làm auth, route, rate limit
Dùng Kafka cho luồng hỏi–đápKhông có phản hồi đồng bộ, độ trễ và độ phức tạp tăngGọi HTTP/gRPC trực tiếp
Manifest chỉ trả một máy chủMột máy lỗi là một phiên xem lỗiTrả danh sách ứng viên đã xếp hạng
Một ladder cố định cho mọi titleThừa bit cho hoạt hình, thiếu bit cho phim hành độngLadder theo nội dung
Tối ưu theo cảnh cho nội dung ít người xemCompute encode không bao giờ được bù lạiChỉ tối ưu sâu cho nội dung xem nhiều
MistakeWhy it’s wrongHow to fix it
Drawing a video system as one pipelineMerges two loads that differ by a factor of millionsSplit control and data planes on the diagram
Routing video through the app serverThe app server becomes an expensive, congested bandwidth pipeReturn a signed URL; let the CDN deliver
Building a CDN because “Netflix does it”The edge comes from scale and ISP relationships, not softwareCommercial CDN until egress is your top cost
Picking Cassandra because it “scales”You lose joins and transactions and must know every query upfrontPostgreSQL first, measure, then split out heavy writes
Treating the cache as storageEviction or restart loses dataThe DB is the source of truth; every key has a TTL
Business logic in the gatewayA second monolith on every requestGateways do auth, routing, rate limiting only
Kafka for request–replyNo synchronous response; more latency and complexityCall HTTP/gRPC directly
A manifest with a single serverOne failing server means one failed sessionReturn a ranked list of candidates
One fixed ladder for every titleWastes bits on animation, starves action scenesContent-aware ladders
Per-shot encoding for rarely watched contentEncode compute is never repaidOptimize deeply only for heavily watched content

Ba câu cần nhớThree things to remember