1. 程式人生 > >增長中的時間序列存儲(Scaling Time Series Data Storage) - Part I

增長中的時間序列存儲(Scaling Time Series Data Storage) - Part I

可能 壓縮存儲 十年 data num 優化 解決 不可 meta

本文摘譯自 Netflix TechBlog : Scaling Time Series Data Storage — Part I

重點:擴容、緩存、冷熱分區、分塊。

時序數據 - 會員觀看歷史

Netflix的用戶,每天觀看1.4億小時的內容。每位用戶在查看影片和保存觀看記錄的時候,都會提供幾個數據點。Netflix分析這些觀看數據並且提供實時的精確書簽和個性化推薦。

觀看歷史數據在如下三個方面增長:

  1. 隨著時間進展,每位會員都會有更多的觀看數據需要被保存。
  2. 隨著會員數量增長,更多的會員的觀看數據需要被保存。
  3. 會員每月觀看時間在增加,每位會員都有更多的觀看數據需要被保存。

隨著Netflix在第一個十年增長到了1億全球會員,這裏有觀看歷史數據也有了巨大的增長。這邊文章重點關註,怎樣面對持續增長的觀看歷史數據的巨大挑戰。

簡單的開始

第一個雲原生的版本使用了Cassandra。

在最初的版本裏,每位會員的觀看數據被以一個單獨行保存在了Cassandra裏。這使得會員增長的擴容變得很高效,並且讀一位會員的完整觀看記錄變得簡單高效。但是隨著會員的增加,更重要的是每位會員觀看了更多的影片,每行的大小以及總體的大小都在增長。

技術分享圖片

當每位會員的觀看數據變多的時候,讀有很多列的行就會成為很大的壓力。

緩存層

Cassandra在寫觀看歷史數據方面工作的很好,但是需要去優化讀延遲的問題。為了優化讀延遲,在增加寫工作的代價下,我們在Cassandra存儲前添加了一個內存中的分片緩存層(EVCache)。每個想Cassandra的寫,都會導致一個額外的緩存查找,並且在緩存命中的時候新數據會和已存在的值合並。觀看歷史讀請求會先被緩存服務。如果緩存未命中,條目會從Gassandra中讀取,並且被壓縮然後插入到緩存中。

配合著額外的緩存層,單一的Cassandra表存儲方式在很多年都工作的很好。基於CustomerId的分區,在Cassandra集群上也擴容的很好。到2012年,觀看歷史的Cassandra集群,已經是Netflix最大的Cassandra集群。

重新設計:實時和壓縮存儲方式

為了可以設計出足以滿足未來5年增長預期的方式,團隊分析了數據的特點和數據模式,然後圍繞兩個主要目標重新設計了觀看歷史的存儲:

  1. 更小的存儲空間。
  2. 隨著每位會員的觀看增長,保持讀寫性能的一致性。

對於每位會員,觀看歷史數據被分成了兩個部分:

  • 實時或者最近觀看歷史(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飛速增長的觀看數據的頭部空間。

技術分享圖片

在下一部分,會解釋最近的擴容挑戰,促進了下一個觀看歷史數據存儲架構的叠代。

增長中的時間序列存儲(Scaling Time Series Data Storage) - Part I