增長中的時間序列儲存(Scaling Time Series Data Storage) - Part I
重點:擴容、快取、冷熱分割槽、分塊。
時序資料 - 會員觀看歷史
Netflix的使用者,每天觀看1.4億小時的內容。每位使用者在檢視影片和儲存觀看記錄的時候,都會提供幾個資料點。Netflix分析這些觀看資料並且提供實時的精確書籤和個性化推薦。
觀看歷史資料在如下三個方面增長:
- 隨著時間進展,每位會員都會有更多的觀看資料需要被儲存。
- 隨著會員數量增長,更多的會員的觀看資料需要被儲存。
- 會員每月觀看時間在增加,每位會員都有更多的觀看資料需要被儲存。
隨著Netflix在第一個十年增長到了1億全球會員,這裡有觀看歷史資料也有了巨大的增長。這邊文章重點關注,怎樣面對持續增長的觀看歷史資料的巨大挑戰。
簡單的開始
第一個雲原生的版本使用了Cassandra。
在最初的版本里,每位會員的觀看資料被以一個單獨行儲存在了Cassandra裡。這使得會員增長的擴容變得很高效,並且讀一位會員的完整觀看記錄變得簡單高效。但是隨著會員的增加,更重要的是每位會員觀看了更多的影片,每行的大小以及總體的大小都在增長。
當每位會員的觀看資料變多的時候,讀有很多列的行就會成為很大的壓力。
快取層
Cassandra在寫觀看歷史資料方面工作的很好,但是需要去優化讀延遲的問題。為了優化讀延遲,在增加寫工作的代價下,我們在Cassandra儲存前添加了一個記憶體中的分片快取層(EVCache)。每個想Cassandra的寫,都會導致一個額外的快取查詢,並且在快取命中的時候新資料會和已存在的值合併。觀看歷史讀請求會先被快取服務。如果快取未命中,條目會從Gassandra中讀取,並且被壓縮然後插入到快取中。
配合著額外的快取層,單一的Cassandra表儲存方式在很多年都工作的很好。基於CustomerId的分割槽,在Cassandra叢集上也擴容的很好。到2012年,觀看歷史的Cassandra叢集,已經是Netflix最大的Cassandra叢集。
重新設計:實時和壓縮儲存方式
為了可以設計出足以滿足未來5年增長預期的方式,團隊分析了資料的特點和資料模式,然後圍繞兩個主要目標重新設計了觀看歷史的儲存:
- 更小的儲存空間。
- 隨著每位會員的觀看增長,保持讀寫效能的一致性。
對於每位會員,觀看歷史資料被分成了兩個部分:
- 實時或者最近觀看歷史(LiveVH): 更少數量的最近觀看記錄,更頻繁的更新。這部分資料以未壓縮的格式,儲存在上述的簡單設計裡。
- 壓縮或者歸檔的觀看歷史(CompressedVH): 更大數量的老觀看記錄,更少的更新。資料被壓縮以減少儲存空間。壓縮後的觀看記錄,儲存在每個row key中的單一行裡。
LiveVH和CompressedVh唄儲存在不同的表裡,並且經過不同的調校去達到更好的效能。
寫流程
新的觀看記錄,使用和上邊描述一樣的方式寫入LiveVH。
讀流程
為了能夠從新設計中獲益,觀看歷史的API被更新增加了帶有讀最近或全部資料的選項。
- 最近觀看歷史:對於大多數情況,結果只從LiveVH裡讀取。限制了資料大小以獲得低得多的延遲。
- 完整觀看歷史:從LiveVH 和 CompressedVH 中並行讀來實現。由於資料壓縮以及CompressedVH有更少的列,更少的資料被讀取;因此讀速度有了顯著的提高。
CompressedVH 更新流程
在從LiveVH中讀觀看歷史記錄的時候,如果記錄的數量超過了配置的閾值,最近觀看記錄會一個後臺任務被彙總、壓縮、儲存在CompressedVH裡。彙總的資料會帶row key:CustomerId被儲存在CompressedVH中。新彙總的記錄會被記錄版本,並且在被寫入後會被讀取檢查一致性。只有在驗證過新版本的一致性後,舊版本的彙總資料會被刪除。
通過分塊自動擴容
對於大部分會員來說,在一行裡儲存壓縮後的全部觀影資料,在讀流程裡有著很好的效能。但是由於少量的有著非常大觀影歷史的會員來說,從CompressedVH的單行裡讀取記錄由於和上述類似的原因開始變慢。所以需要對這種少見的情況有個上限,並且避免影響到正常情況的讀寫延遲。
為了解決這些問題,如果資料大小超過了配置的閾值,我們會把彙總壓縮的資料分成了幾塊。這些塊儲存在不同的Cassandra節點上。這樣並行讀寫這些塊使得即使非常大的觀看記錄也可以有個讀寫延遲的上限。
寫流程
依照配置的塊大小,彙總壓縮的資料被拆封到多個塊裡。所有的塊並行寫到不同的行裡,使用row key: CustomerId$Version$ChunkNumber. 在寫完前邊的塊資料之後,Metadata 被寫到他單獨的行裡,使用row key: CustomerId。
讀流程
先通過CustomerId的key讀metadata。每次讀最多延遲成兩次讀。
快取層變化
對於有很大觀看記錄的會員來說,把全部快取記錄儲存在一個EVCache entry是不可能的。所以和CompressedVH模型類似,每個大觀看記錄快取單元會被拆成多個塊,metadata儲存在第一個塊裡。
結果
在並行,壓縮,和改進過的資料模型的共同作用下,這個團隊完成了所有的目標。
- 通過壓縮打到更小的儲存空間
- 通過分塊和並寫讀寫,達到了一致性讀寫效能。
團隊減少了6倍的資料空間,減少13倍的Cassandra的維護時間,減小了5倍的平均讀延遲,和1.5倍的平均寫延遲。更重要的是,給了團隊一個可擴容的架構,和課協調Netflix飛速增長的觀看資料的頭部空間。
在下一部分,會解釋最近的擴容挑戰,促進了下一個觀看歷史資料儲存架構的迭代。