Netflix是全球最大的在線視頻網站之一,它是怎麼設計的呢?這篇文章介紹了Netflix系統架構的設計方案。原文:Netflix System Architecture[1]
我們來討論一下如何設計Netflix。
相信每個人都會通過某些網站或應用在線追劇或者看電影,而Netflix是我最喜歡的在線視頻網站,不過今天我不推薦任何電影,相反,我想展示的是Netflix背後令人驚豔的系統邏輯。
功能性需求創建帳戶、登錄、刪除帳戶
訂閱或取消訂閱不同的計劃
允許用戶擁有和處理多個帳戶
允許用戶觀看視頻
允許用戶下載視頻並離線觀看
允許用戶通過視頻標題搜索和發現視頻
Netflix製作人可以從後臺上傳視頻並在平臺上展示
平臺可以顯示趨勢、最受歡迎的視頻和分類,以方便用戶選擇
可以選擇不同語言的字幕,這樣用戶即使聽不懂這些語言,也可以觀看視頻
視頻分組(劇集、娛樂節目、電影,單獨處理每個視頻)
根據用戶行為進行分析,為用戶推薦類似的視頻
在同一帳號下的不同設備之間進行同步,用戶可以使用不同的設備繼續觀看同一視頻而無需重播
支持全天候(24/7)回放
支持回退
非功能性需求用戶可以觀看實時視頻流,沒有任何卡頓或延遲問題
系統是高度可靠的
高可用
可擴展
視頻數據持久化且易於訪問
容量預估我們可以基於一些數學計算來估計所需的帶寬和存儲空間。
日活用戶總數 = 1億
日活峰值用戶:1億 * 3 = 3億
3個月最大日活峰值用戶:3億 * 2 = 6億
每個用戶每天平均觀看的視頻數 = 5
視頻平均大小 = 500 MB
後臺平均每天上傳的視頻數 = 1000
每天觀看的總視頻數 = 1億*5 = 5億
每天觀看的總視頻峰值 = 15億
每天觀看的最大視頻峰值 = 30億
每天總出口流量 = 5億* 500 MB = 250 PB (Peta Byte)
出口帶寬 = 29.1 GB/秒
每天上傳總入口流量 = 1000 * 500MB = 500 GB
入口帶寬 = 5.8 MB/秒
5年所需的總存儲空間 = 500 GB * 5 * 365 = 912.5 TB(請注意,Netflix會為每個視頻準備多種格式和解析度的版本,可針對不同類型設備進行優化,所以存儲空間將超過912.5 TB)。
1. 客戶端應用
手機(iOS,Android,華為,等等)
平板(iPad,Android,Windows)
電視
電腦
基於React.js實現的前端可以擁有較好的加載/啟動速度、持久性/模塊化和運行時性能。
2. 後端
Netflix從2011年開始實施微服務架構,完全基於雲來管理工作負載。通過小型、可管理的API組件支持並處理來自應用程式和網站的請求,微服務內部通過請求和獲取數據而相互依賴。後端技術棧包括了Java, MySQL, Gluster, Apache Tomcat, Chukwa, Cassandra, KAFKA和Hadoop。後端系統不單單需要處理流媒體視頻,還需要處理其他所有事情,比方說數據處理、加載新內容、網絡流量管理、全球資源分發等。Netflix目前部署在AWS之上。
數據處理涉及點擊視頻後發生的所有事件,系統需要在幾納秒的時間內處理完視頻並將其傳輸給用戶。整個系統每天大約需要處理6000億個事件,產生1.5PB的數據,在高峰期(傍晚和夜間)每秒大約需要處理800萬個事件。這些事件包括UI活動、視頻查看活動、日誌錯誤、故障排除、診斷事件、處理事件和性能事件等。所有這些事件都是通過Kafka和Apache Chukwe完成的。
Kafka和Apache Chukwe
從系統的不同部分獲取產生的數據。
Apache Chukwe是一個開源數據收集系統,用於從分布式系統中收集日誌或事件。它建立在HDFS和Map-reduce框架之上,具有Hadoop的可伸縮性和健壯性特性。此外,它還包含許多功能強大、靈活的工具箱,用於顯示、監控和分析結果。Chukwe從系統的不同部分收集事件,並提供儀錶盤幫助我們進行事件的查看、監控和分析。Chukwe以Hadoop文件序列格式(S3)寫入事件,大數據團隊可以處理這些S3 Hadoop文件,並以Parque格式將數據寫入Hive。這個過程被稱為批處理,基本上以每小時或每天的頻率掃描整個數據。為了將在線事件上傳到EMR/S3, Chukwa還向Kafka(實時數據處理的入口)提供流量。Kafka負責將數據從前端Kafka注入到不同的後端: S3, Elasticsearch和下遊Kafka,消息的路由可以通過Apache Samja框架完成。通過Chukwe發送的流量既可以是完整的流也可以是過濾過的流,所以有時候你可能需要對Kafka流量進行進一步過濾,這就是我們需要考慮將流量從一個Kafka topic路由到另一個Kafka topic的原因。
Elastic Search
Netflix目前有大約150個Elastic Search集群,其實例分布在3500個主機上。
Netflix通過Elastic Search來實現數據的可視化、客戶支持以及系統中的錯誤檢測。例如,如果客戶無法播放視頻,那麼客戶服務主管將利用Elastic Search來解決問題。回放團隊會去Elastic Search搜索該用戶,試圖找到為什麼視頻不能在用戶設備上播放的原因。他們可以了解特定用戶所發生的所有信息和事件,知道是什麼導致了視頻流出錯。系統管理員還可以基於Elastic Search跟蹤某些信息,比如跟蹤資源使用情況、檢測註冊或登錄問題等。
後端服務
用戶和認證服務(主要負責用戶認證和配置文件)。數據存儲在關係型資料庫中,如MySQL或PostgreSQL。
訂閱管理服務(管理用戶的訂閱)。由於該服務處理的數據本質上是高度事務性的,因此RDBMS是一個合適的選擇。
視頻服務(向終端用戶提供視頻)。這個服務將視頻元數據存儲在RDBMS中,比如MySQL或PostgreSQL。為了獲得更快的響應時間,該服務將使用Redis或Memcached這樣的內存緩存來實現繞寫(write-around)緩存。
轉碼服務(檢查上傳視頻的質量,用不同的編解碼器壓縮視頻,創建不同解析度版本)。一旦視頻被上傳到Transcoder服務,它將把視頻上傳到內部分布式存儲,比如S3,並向資料庫添加條目。Kafka或RabbitMQ在隊列中處理消息,後端工作組件收到隊列的消息,內部S3下載視頻,並將其轉碼為不同的格式。轉碼完成後,後端工作組件將視頻上傳到外部S3,並將資料庫中的視頻狀態更新為active,供終端用戶查看。後端工作組件還會在支持全文搜索的搜索資料庫中添加視頻元數據條目,這樣終端用戶就能夠使用標題或摘要搜索視頻。外部S3存儲的視頻也將通過CDN緩存,以減少延遲,提高播放性能。
全球搜索服務(允許終端用戶使用元數據,如標題、摘要等搜索視頻)。元數據存儲在Elastic Search資料庫中,因此可以基於Elasticsearch或Solr支持全文搜索,用戶可以根據標題搜索電影、劇集或與視頻相關的任何元數據。該服務還可以根據最近觀看、評論、推薦和流行程度對結果進行排名,以獲得更好的用戶體驗。此外,Elastic Search可以在失敗的情況下跟蹤用戶事件,客戶服務團隊可以使用Elastic Search來解決問題。
3. 雲
4. CDN
一個全球分布的伺服器網絡集群。當我們播放視頻的時候,設備上顯示的視頻將從最近的CDN伺服器獲取,從而極大降低響應時間。
CDN在多個地方複製內容,這樣視頻可以更貼近用戶,傳輸距離更短。
CDN機器大量使用緩存,所以即使沒有從伺服器上找到視頻,也可以從緩存中獲取。
CDN不會緩存不太受歡迎的視頻(比方說每天只有不到20次觀看量的視頻)
5. Open connect[2]
Netflix的內部定製全球CDN,負責向全球Netflix用戶存儲和傳送電影和電視節目。當我們按下播放按鈕,視頻就會從全球不同位置的Open connect伺服器中傳輸給我們。如果視頻已經緩存在Open connect伺服器上,客戶端可以輕鬆訪問到,而如果視頻沒有被緩存,Netflix必須從AWS的S3存儲中獲取並處理該視頻,然後Open connect才可以將該視頻流推送到客戶端應用程式。
6. 緩存
Redis和Memcached以鍵值對的方式緩存資料庫中的數據,可以有效減少對資料庫的訪問。客戶端通過伺服器訪問資料庫之前,系統會檢查緩存中是否有數據,如果有,就可以繞過資料庫訪問。但是,如果數據不在緩存中,必須訪問資料庫並獲取數據,並在緩存中填充相同的數據。因此,隨後的請求就不需要訪問資料庫了。這種緩存策略稱為繞寫(write-around)緩存。我們使用最近最少使用(LRU)策略作為緩存數據的驅逐策略,最早獲取的緩存將會被丟棄。
Netflix在AWS EC2上部署了很多集群,這些集群包含有很多Memcached節點以及緩存客戶端。數據在同一個分區的集群中共享,多個緩存副本存儲在分片節點中。每次當客戶端寫入數據時,所有集群中的所有節點都會被更新,但當讀取數據時,讀取操作只會被發送到最近的集群及其節點上,如果某個節點不可用,則從另一個可用節點讀取。這種方法提高了性能、可用性和可靠性。
7. 可擴展性
水平擴展——在負載均衡器後面增加更多的應用伺服器,以增加服務的容量。
資料庫備份——關係資料庫配置為主從關係,寫操作發生在主資料庫上,從從資料庫讀取數據。讀操作不會因為寫操作而被鎖住,因此可以提高讀查詢的性能。當數據寫入主資料庫並複製到從資料庫時,會有輕微的複製延遲(幾毫秒)。
資料庫分片——將數據分布到多個伺服器上,以便高效的進行讀寫操作。比方說,我們可以使用video_id對視頻元數據資料庫進行分片,哈希函數把每個video_id隨機映射到一個伺服器上,從而存儲對應的視頻元數據。
緩存分片——將緩存分發到多個伺服器上。Redis支持跨多個實例劃分數據,為數據分布使用一致的哈希算法確保在一個實例消失時保持負載均勻分布。
搜索資料庫分片——Elasticsearch原生支持分片和備份。通過在多個分片上並行運行分片,有助於改進查詢運行時。
8. 安全
9. 彈性
10. 負載均衡
負載均衡器負責將流量路由到前端服務。ELB(Elastic load balancing,彈性負載均衡)執行兩層負載均衡方案,首先基於區域(zone)進行負載均衡,然後對實例(伺服器)進行負載均衡。
11. Geo-redundancy
12. ZUUL
提供動態路由、監控、彈性和安全性,支持基於查詢參數、URL路徑的簡單路由。
Netty伺服器負責處理網絡協議、web服務、連接管理和代理工作。當請求到達Netty伺服器時,它負責將請求轉發到入口過濾器。
入口過濾器(The inbound filter)負責身份驗證、路由或裝飾請求。然後將請求轉發給端點過濾器。
端點過濾器(Endpoint filter)用於返回靜態響應,或者將請求轉發到後端服務。一旦它從後端服務接收到響應,就將請求發送到出口過濾器。
出口過濾器(Outbound filter)用於壓縮內容、計算指標或添加/刪除自定義標頭。在此之後,響應被發送回Netty伺服器,然後發送給客戶端。
優勢:
可以創建規則,將流量的不同部分分配到不同的伺服器,從而實現對流量的分片。
開發人員可以在某些機器上對新部署的集群進行負載測試,可以在這些集群上路由部分現網流量,並檢查特定伺服器可以承受多少負載。
可以用於測試新服務。當我們需要升級服務並希望檢查該服務如何處理實時API請求時,可以將特定服務部署在一臺伺服器上,並將部分流量重定向到新服務,以便實時檢查該服務狀態。
可以通過在端點過濾器或防火牆上設置自定義規則來過濾惡意請求。
13. Hystrix
在一個複雜的分布式系統中,一個伺服器可能依賴於另一個伺服器的響應。這些伺服器之間的依賴關係可能會造成延遲,如果其中一個伺服器在某個時刻不可避免的出現故障,整個系統可能都會停止工作。為了解決這個問題,可以將主機應用程式與這些外部故障隔離開來。Hystrix庫就是為此而設計的,通過添加延遲容忍和容錯邏輯,幫助我們控制分布式服務之間的交互。Hystrix通過隔離服務、遠程系統和第三方庫之間的訪問點來實現這一點。Hystrix可以幫助我們實現:
資料庫組件Netflix使用不同的DB來存儲不同類型的文件,例如用於不同目的的SQL和NoSQL。
1. MySQL
符合ACID,因此可用於管理影片標題、計費和事務用途。
在AWS EC2上部署MySQL來存儲數據
MySQL配置為主主模式,在大型AWS EC2實例上使用InnoDB引擎構建。
設置遵循「同步複製協議(Synchronous replication protocol)」。數據複製是同步完成的,表明節點之間存在主主關係,只有當數據由本地和遠程節點同步以確保高可用性時,才會認為主節點上的任何寫操作已經完成。讀查詢不是由主節點處理,而是由副本處理,只有寫查詢是由主資料庫處理。在故障轉移的情況下,副節點將作為主節點,並將負責處理寫操作。
2. Cassandra (NoSQL)
Cassandra是開源的、分布式的、基於列的NoSQL資料庫,可以在伺服器上存儲大量數據。Netflix使用Cassandra來存儲用戶歷史。它可以有效處理大量讀請求,並優化大量讀請求的延遲。隨著用戶群的增長,存儲多行數據變得越來越困難,而且成本高且速度慢。所以,Netflix設計了基於時間框架和最近使用的新資料庫。
當Netflix的用戶越來越多時,每個用戶的觀看歷史數據也開始增加。
更小的存儲空間開銷。
隨著用戶查看次數的增長而增長的一致性讀寫性能(在Cassandra中查看歷史數據寫讀比約為9:1)。
非規範化數據模型
超過50個Cassandra集群
超過500個節點
每天超過30TB的備份數據
最大集群有72個節點
每個集群超過250K每秒寫操作
最初,觀看歷史記錄存儲在Cassandra的單行中。當Netflix的用戶越來越多,行數和總體數據大小都增加了。這導致了更高的存儲成本、更高的操作成本和更低的應用程式性能。解決方案是壓縮舊的行…
資料庫定義
用戶註冊
請求:
POST /api/v1/users
X-API-Key: api_key
{
name:
email:
password:
}
通過HTTP POST方法,在資料庫中創建一個資源或新條目。X-API-Key是傳遞給HTTP報頭的API key,用於識別不同的客戶端並進行速率限制。
響應:
201 Created
{
message:
}
HTTP狀態碼201告訴用戶已成功註冊。用於失敗情況的其他可能的HTTP狀態碼:
400 Bad Request
409 Conflict
500 Internal Server Error
用戶登錄
請求:
POST /api/v1/users/session
X-API-Key: api_key
{
email:
password:
}
響應:
200 OK
{
auth_token:
}
API應該返回一個auth_token,它可以在header中傳遞給需要認證的後續API調用。auth_token可以使用JWT[3]生成。
用戶登出
請求:
DELETE /api/v1/users/session
X-API-Key: api_key
Authorization: auth_token
使用HTTP DELETE方法刪除資料庫中的行條目,意味著我們正在終止一個會話。
響應:
200 OK
HTTP狀態碼200表示成功登出。
訂閱
請求:
POST /api/v1/subscription
X-API-Key: api_key
Authorization: auth_token
HTTP POST方法創建一個新的訂閱,在Authorization頭中傳遞auth-token來驗證用戶。
響應:
201 Created
{
subscription_id:
plan_name:
valid_till:
}
HTTP狀態碼201與subcription_id、plan_name和valid_till一起在用戶界面中呈現。
可能的HTTP失敗狀態碼:
401 Unauthorized
400 Bad request
取消訂閱
請求:
DELETE /api/v1/subscription
X-API-Key: api_key
Authorization: auth_token
HTTP DELETE方法是可以取消訂閱,該接口將從訂閱資料庫中刪除一個行條目。
響應:
200 OK
HTTP狀態碼200意味著成功完成。
批量獲取視頻
請求:
GET /api/v1/videos?page_id=<page_id>
X-API-Key: api_key
Authorization: auth_token
該API用於在登錄後呈現主頁,包含了由機器學習模型確定的推薦視頻。page_id用於API中的分頁,next_page_id用於從下一頁請求結果。
響應:
200 OK
{
page_id:
next_page_id:
videos: [
{
id:
title:
summary:
url:
watched_till:
},...
]
}
HTTP狀態碼200表示操作成功。
其他故障狀態碼:
401 Unauthorized
500 Bad request
429 Too many requests
HTTP狀態碼429意味著用戶達到速率限制,需要等待一段時間才能再次發出請求,以避免拒絕服務攻擊。
搜索API
請求:
GET /api/v1/search?q=<query>&page_id=<page_id>
X-API-Key: api_key
Authorization: auth_token
通過標題搜索視頻。
響應:
200 OK
{
page_id:
next_page_id:
videos: [
{
id:
title:
summary:
url:
watched_till:
},...
]
}
HTTP狀態碼200表示操作成功,響應中包括了id、title、summary、url和watched_till等信息,不過也有可能找不到相關視頻。
獲取視頻
請求:
GET /api/v1/videos/:video_id
X-API-Key: api_key
Authorization: auth_token
播放特定視頻。
響應:
200 OK
{
id:
title:
summary:
url:
watched_till:
}
HTTP狀態碼200表示匹配到了視頻。
其他故障狀態碼:
401 Unauthorized
404 Video not found
429 Too many requests
500 Internal server error
上傳API
請求:
POST /api/v1/videos
X-API-Key: api_key
Authorization: auth_token
{
title:
summary:
censor_rating:
video_contents:
}
從後臺上傳視頻。
響應:
202 Accepted
{
video_url:
}
HTTP狀態代碼202表示視頻已經排隊進行異步處理和質量檢查,處理結果可以通過電子郵件或其他告警機制發送給用戶。
一些HTTP失敗的場景:
401 Unauthorized
400 Bad request
500 Internal server error
更新觀看時間戳
請求:
PUT /api/v1/videos/:video_id/watched_till
X-API-Key: api_key
Authorization: auth_token
{
watched_till:
}
之所以使用HTTP PUT方法,是因為我們需要用其他數據替換同一個資料庫表中的行條目,或者我們需要更新伺服器上的資源。這個API將用於更新時間戳,直到用戶看完了特定的視頻。
響應:
200 OK
HTTP狀態碼200表示操作成功。
其他HTTP失敗狀態碼:
401 Unauthorized
400 Bad request
500 Internal server error
由於服務中的任何更改都可以很容易完成,因此微服務可以更快的完成部署。可以跟蹤每個服務的性能,如果有任何問題,則可以快速將其與其他正在運行的服務隔離開來。
關鍵服務——為經常與該服務交互的用戶提供服務。這些服務獨立於其他服務,以便在進行任何故障轉移時,用戶可以繼續執行基本操作。
無狀態服務——向客戶端提供API請求,即使有任何伺服器出現故障,也可以繼續與其他實例一起工作,從而確保高可用性。例如,REST API服務為最多的用戶提供服務。
上傳的內容是視頻格式的電影或劇集,處理單元包括了輸入協議、輸入編解碼器、輸出編解碼器和輸出協議,以服務於各種設備和不同的網絡速度。當我們在高速網絡上觀看視頻時,視頻的質量很好。Netflix為同一部電影創建不同解析度的多個副本(大約1100-1200個)。Netflix將原始視頻分成不同的小塊,並在AWS中使用並行工作單元將這些小塊轉換成不同的格式。這些處理單元用於編碼或轉碼,即將視頻從一種格式轉換為另一種格式,如改變解析度,高寬比,減少文件大小等。在轉碼之後,一旦我們擁有同一電影的多個文件副本,這些文件就被傳輸到Open connect伺服器。
系統架構概要設計電影推薦使用Apache Spark和機器學習。當載入所觀看的首頁時,會有好幾行不同類型的電影。
Netflix希望用戶最大限度的點擊視頻,而這些點擊取決於標題圖像。Netflix必須為特定的視頻選擇正確的引人注目的標題圖像。為了做到這一點,Netflix為一部特定的電影創建了多個藝術作品,並隨機向用戶展示這些圖像。對於同一部電影,不同的用戶可以使用不同的圖像。根據用戶的喜好和觀看歷史,Netflix會預測用戶最喜歡哪類電影,或者最喜歡哪位演員。Netflix將根據用戶的口味,顯示合適的圖像。
Netflix會分析數據,從而決定應該向用戶展示什麼樣的電影,這是基於用戶的歷史數據和偏好計算的。此外,Netflix還會對電影進行排序,並計算這些電影在其平臺上的相關性排名。大多數機器學習流水線都運行在這些大型Spark集群上,然後使用這些流水線進行選擇、排序、標題相關性排名和藝術品個性化等操作。當用戶打開Netflix的首頁時,用戶就會被每個視頻顯式的圖像所吸引。
現在,Netflix還會計算特定圖像被點擊的次數。如果電影的中心圖像的點擊量是1500次,而其他圖像的點擊量更少,那麼Netflix就會讓中心圖像永遠作為電影《心靈捕手》的標題圖像。這被稱為數據驅動,Netflix用這種方法執行數據分析。為了做出正確的決策,需要根據與每張圖片關聯的訪問數量計算數據。
用戶與服務的交互(觀看歷史記錄以及評價)。
有相似品味和喜好的其他用戶。
用戶先前觀看的視頻的元數據信息,如標題、類型、類別、演員、發行年份等。
用戶的設備、活躍時間以及活躍時長。
兩種類型的算法:
1. 協同過濾算法:這種算法的思想是,如果兩個用戶有相似的評級歷史,那麼他們將在未來的行為相似。例如,假設有兩個人,一個人喜歡這部電影,給它打了高分,那麼另一個人也很可能會喜歡這部電影。
2. 基於內容的推薦:這個算法的思想是,過濾那些與用戶之前喜歡的視頻相似的視頻。基於內容的過濾高度依賴於電影名稱、發行年份、演員、類型等信息。因此,要實現這種過濾,重要的是要知道描述每個項目的信息,還需要一些描述用戶喜好的用戶配置文件。
https://towardsdatascience.com/deep-dive-into-netflixs-recommender-system-341806ae3b48
https://netflixtechblog.com/announcing-suro-backbone-of-netflixs-data-pipeline-5c660ca917b6
https://keypointt.com/2020-05-16-Netflix-playback-dive-deep/
https://www.nexsoftsys.com/articles/how-netflix-backend-system-operates.html
https://elatov.github.io/2021/02/distributed-systems-design-netflix/
https://developpaper.com/design-and-analysis-of-netflix-microservice-architecture/
https://uxdesign.cc/netflix-system-design-ef5802426ad4
https://netflixtechblog.com/tagged/cloud-architecture
https://www.codingninjas.com/blog/2020/12/04/learn-what-is-rest-api-in-10-minutes/
https://about.netflix.com/en/news/how-netflix-works-with-isps-around-the-globe-to-deliver-a-great-viewing-experience
https://www.infoq.com/news/2019/01/netflix-evolution-architecture/
https://www.codekarle.com/system-design/netflix-system-design.html
http://highscalability.com/blog/2015/11/9/a-360-degree-view-of-the-entire-netflix-stack.html
https://www.youtube.com/watch?v=lYoSd2WCJTo
References:
[1] Netflix System Architecture: https://medium.com/interviewnoodle/netflix-system-architecture-bedfc1d4bce5
[2] Netflix Open Connect: https://openconnect.netflix.com/en/
[3] JSON Web Tokens Introduction: https://jwt.io/introduction/
你好,我是俞凡,在Motorola做過研發,現在在Mavenir做技術工作,對通信、網絡、後端架構、雲原生、DevOps、CICD、區塊鏈、AI等技術始終保持著濃厚的興趣,平時喜歡閱讀、思考,相信持續學習、終身成長,歡迎一起交流學習。
微信公眾號:DeepNoMind