小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

ITPUB社群發表於2022-11-25

RedKV是小紅書自研的一款基於NVMeSSD的分散式NoSQL KV儲存系統,支援無中心和有中心的兩種管控架構,旨在解決公司內實時落盤的KV儲存需求。RedKV1.0基於Gossip協議做節點管理,在全公司已經大規模使用,實時QPS接近1億/秒,儲存量在數PB級別。RedKV2.0採用中心Shard管理架構,支援全球多雲多副本線上彈性伸縮,異地容災和服務秒級切換


透過分層最佳化,RedKV對比開源同類產品,聚合寫吞吐能力平均提升3倍,讀1.5倍;對標HBase,成本最佳化近40%。RedKV部分相容Redis協議,string/hash/zset等主要資料型別很好的的支援了公司的絕大部分線上儲存業務,最佳化了早期Redis叢集部署產生的成本問題以及HBase帶來的效能及穩定性問題。RedKV和Hive數倉的資料互通能力為離線資料業務提供了一種解決方案。

1

小紅書是年輕人的生活記錄、分享平臺,使用者可以透過短影片、圖文等形式記錄生活點滴,分享生活方式。在當前的業務模型下,使用者的畫像資料和筆記資料用來做風險控制和內容推薦。儲存資料具有物件-屬性的特徵、維度多,畫像資料量已經達到數十TB, 線上業務對畫像和筆記資料的訪問P99 時延要求非常高。


2020年之前公司選擇的NoSQL儲存產品主要有:Redis、HBase,隨著公司DAU的高速增長,早期的儲存方案遇到如下挑戰:

  • Redis叢集主要適用於快取場景,開啟AOF資料實時落盤對效能有比較大的影響,同時每個節點需要額外掛載雲盤用於儲存AOF。在叢集節點和儲存容量受限的情況下,單節點的資料量設定過大會導致故障後節點資料的failover時間太長,單節點資料量設定小會導致gossip協議在穩定性高要求下節點個數受限,同時考慮突發流量的壓力,Redis叢集在部署上需要做一些空間預留,帶來成本高的問題。

  • HBase作為一款生態完善的NoSQL儲存系統,在高QPS下也產生了諸多的效能和穩定性問題,如:Zookeeper壓力大時穩定性難以保障(節點探活,服務註冊等都依賴 Zookeeper);HBase的資料檔案和WAL日誌檔案直接寫HDFS,節點故障後,重放HDFS上的WAL速度慢;Java GC會導致Zookeeper誤殺RegionServer,同時產生毛刺;Major Compaction 會導致I/O飆升,產生長尾效應;受限HDFS的複雜性,黑盒運維對工程師來說比較困難;在小紅書的業務實戰中,百萬QPS下HBase延時不太理想,核心資料用大記憶體機型兜住,也引發成本高的問題。


隨著業務的持續增長,開源儲存產品已經不能很好的滿足公司的業務發展需求, 公司需要一款穩定的高效能KV系統支撐內部業務,一方面要滿足業務對功能和效能的需求,另一方面要最佳化成本。

2


2.1. 高QPS和低延時讀取特性

特徵資料儲存場景:

  • 寫入頻寬達到數十GB/s,要求實時寫入效能和讀取效能都很高。


圖片快取的場景:

  • 資料量很大,要求讀取時延低。可以接受故障場景下少量資料丟失。


高效能(P99 < 10ms):

  • 模型資料儲存服務。記錄過去一段時間使用者訓練模型資料,對P99時延要求非常高,資料量在幾十TB。

  • 去重儲存服務。資料量在幾十TB,P99<10ms, P999<20ms。

  • 風控資料儲存服務。QPS目前達到千萬級別,P999 < 30ms。


2.2. 低成本的快取特性

對標Redis:

  • 相容Redis協議,效能比Redis慢一些,但資源成本降低50%+。


典型場景:

  • 廣告的關鍵詞儲存和反作弊業務,解決大資料量、低QPS的儲存模型。


2.3. NoSQL儲存特性

對標HBase:

  • 支援資料多版本,列存行取等特性,比HBase成本減少30%+,P99時延提升6倍。

  • 支援KKV級別的TTL。

  • 強一致:目前RedKV1.0採用的主從雙副本,資料寫入成功,可以透過配置同步模式來保障2副本寫成功,讀主寫主保障強一致。對於寫效能要求高的場景,可以開啟非同步寫,寫主成功則返回,依賴增量同步從節點資料。


典型場景:

  • 風控服務。實時查詢對P999要求極高,千萬QPS下HBase已經不能滿足效能需求,時延抖動比較大。

  • 畫像儲存服務。資料的維度多,欄位讀取的業務方多,對時延要求敏感。

3

RedKV整體架構分3層,接入層相容Redis協議,支援各種語言的社群版SDK和公司定製的中介軟體版;接入代理層支援千萬QPS的讀寫能力,無狀態擴充套件;儲存層提供高可靠讀寫服務。RedKV1.0架構如下圖1,下面我們詳細的展開3層元件的介紹。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖1. RedKV1.0整體架構


3.1. Client接入層

RedKV叢集部署完成後,透過公司內部提供的Service Mesh元件做服務發現,對Client提供服務。


3.2. Proxy

Proxy層由一個無狀態CorvusPlus程式組成。它相容老的Redis Client,擴縮容、升級對無Client和後端叢集無感,支援多執行緒、IO多路複用和埠複用特性。對比開源版本,CorvusPlus增強了自我防護和可觀測特性,實現了可線上配置的功能特性:

  • Proxy限流

  • 資料線上壓縮

  • 執行緒模型最佳化

  • backup-read最佳化長尾

  • 大key檢測


3.2.1. Proxy限流

小紅書當前的業務模型比較多,客戶端行為無法預期,可能出現的發版錯誤、系統問題及網路抖動引發客戶端重試,突發的qps會影響服務穩定性。在高QPS壓力下,Proxy處理客戶端讀寫超時,大量重試會導致雪崩,業務高峰期單個 Proxy 頻寬可能超過機器的出入頻寬限制,而儲存叢集只能保證在有限的資源內提供穩定可靠的服務。針對這類場景,我們需要保證流量過載時,Proxy和RedKV服務不被打崩,能保障高可用。


基於以上問題和目標,對比原生的Redis Cluster模式,RedKV基於令牌桶的流控演算法支援了對連線數、頻寬和QPS多維度限流。在高QPS下,我們的Proxy限流防止了雪崩,如圖2;在大頻寬場景下,我們最佳化了時延,如圖3。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖2. 雪崩場景下的限流


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖3. 大頻寬場景下的限流


3.2.2. 資料線上壓縮

Proxy層本身只做路由轉發,對CPU的消耗非常低。在大頻寬的場景下,我們可以充分利用Proxy的CPU資源最佳化頻寬和毛刺。在解析Redis協議時,使用LZ4演算法對寫入資料進行線上壓縮,讀取時線上解壓。在推薦快取的使用場景中網路頻寬和儲存空間壓縮40%以上(如圖4),總體時延並沒有明顯的下降。因為網路頻寬和寫入讀取資料的減少,時延毛刺也變小了。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖4. Proxy開壓縮後的頻寬最佳化


3.2.3. 執行緒模型的最佳化

Proxy採用IO多路複用技術,每個連線維護一個請求處理佇列和響應佇列,保序的返回給客戶端。Proxy在收到RedKV Server的回應之後,如果沒有收到所有傳送的cmd的返回,則會一直等待所有cmd的返回後再傳送給client,對於讀的場景這種模式非常不友好。經過改造,如果某個cmd之前的cmd都已經正常響應,則可以馬上響應給client,不需要再等後面的所有cmd請求完成。


3.2.4. backup-read最佳化長尾

在公網環境下,一個CVM虛擬機器和其他多個虛擬機器共享一臺物理機。當某個客戶的CVM佔用大量資源時,很容易影響到其他CVM的P99時延(由於QOS和隔離性做的不夠好,SMI中斷和記憶體CE)。在網路吞吐較大的情況下,某雲的DPDK容易被打爆,出現母機OOB。而在RedKV的內部實現中,如果Server請求比較大,某些key的查詢時延比較高的時候,容易產生排隊堆積,或者compaction之後的block cache失效,很容易造成IO長尾。因此,RedKV的P99讀時延的毛刺很難避免,但毛刺是偶爾發生的,當前我們的主從節點一定是離散部署在不同的母機上,同時出現P99毛刺的可能很小。基於這點,我們在Proxy層做了backup read功能,最佳化了RedKV的p99時延問題。


針對以上模型,我們的最佳化思路:

  • 檢查節點的狀態和過去的延時

  • 選擇2個節點中狀態好的那個節點傳送請求

  • 計算P99時延,超過P95時延則向另外一個節點傳送一定數目的backup read請求數

  • 兩個請求中任意一個請求返回成功則成功,如果超時則繼續重試


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖5. Backup-read 消峰


因為backup read轉發不需要複製記憶體,透過索引來保證生命週期,而且只有超過P95時延的報文會被檢查是否能傳送backup read,因此,只要5%的報文會傳送兩次,對叢集基本不會增加壓力。圖6為一個叢集中 P999從35ms降低到4ms左右,效果非常明顯。對比HBase同樣的業務場景,客戶端在同樣的timeout的配置下,我們的方案提高了客戶端的成功率。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖6. Backup-read P999最佳化對比


3.2.5. 大Key檢測

我們線上很多叢集在業務使用過程中會偶發的產生一些毛刺,透過抓包發現,這裡毛刺有很大一部分原因是因為大Key造成的。為了甄別這類問題,我們在Proxy層支援的大Key的可觀測指標。Proxy在解析Redis的cmd可以附帶統計KV的大小。對於string讀型別的command,讀到的val值大於 big-string-size 判定為大key;對於寫型別的command, 請求值大於 big-string-size 判定為大key;對於hash/zset則為一次讀取的kv總數大小。透過增加read_size(所有讀請求總共讀到的位元組數) 和 write_size (所有寫請求總共寫入的位元組數)監控,rate(read_size) / rate(total_req_amount) 可以計算出平均請求值大小。大Key和熱Key是KV系統不可避免的2個場景,針對大Key,我們提供了Proxy層的資料壓縮能力;對於熱Key, 我們在Server層基於HeavyKeeper[3]演算法做了topK統計和處理。


3.3. RedKV Cluster

公司的儲存需求場景比較多,如廣告業務儲存的標籤和資料模型很多,同時是非常核心的業務,業務需要做資源隔離。為了減少節點故障縮小資料的爆炸半徑 ,這裡業務我們採用無中心管控的架構,即RedKV1.0架構,它能在部署和運維上能大大簡化。無中心的叢集架構採用的是Gossip協議,儲存節點採用多程式多例項部署,如圖7。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖7. Gossip管控的KV Cluster


推薦模型訓練的資料量非常大,上下游業務很多,承載的QPS高,對應叢集的節點也比較多,在故障處理和擴縮容方面會觸發gossip抖動。針對大叢集的節點管理,我們採用有中心管控的架構,即RedKV2.0架構。基於Shard管理的中心架構能更好的支援資料遷移和叢集擴縮容,儲存節點採用單程式多例項部署,在多活場景中可以支援副本數彈性擴充套件,如圖8。RedKV2.0的相關元件會在後續的技術文章中詳細介紹。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖8. 基於中心管控的KV Cluster


3.3.1. Gossip最佳化

RedKV1.0採用Gossip協議通訊,節點故障時主從節點的切換,最長影響時間為30s。一個節點出現故障時,叢集中正常節點將故障節點標記為 fail 狀態需要經過一段收斂時間。在這段時間內,Proxy層有可能將使用者請求轉發給已經 fail 的節點,導致請求失敗。減小叢集收斂時間能有效減少Proxy層錯誤請求數量,提高叢集的穩定性和可用性。


RedKV1.0透過如下三個步驟加快檢視收斂:

  • 探測時間最佳化:Redis Gossip協議正常情況下會每隔100ms隨機選取一個節點傳送ping包,並更新節點的ping_sent值為傳送ping包時間。如果叢集很大,節點數很多,那麼故障節點被ping到的機率就會變小,最多超過node_timeout/2時間給故障節點傳送ping包。這樣就會導致節點發生故障時,叢集中正常節點不能第一時間ping到故障節點,從而無法立刻感知到故障節點發生了故障。為了減少這部分時間,當叢集中有節點超過2s沒有收到故障節點傳送的pong報文時,就立馬通知其他節點去ping故障節點。這樣可以把節點故障到正常節點給故障節點傳送ping的時間控制在2s左右。

  • 判定PFAIL時間最佳化:Gossip 協議現有實現方式是超過node_timeout(通常為15s)時間沒有收到pong報文,就將節點狀態置為pfail。本次最佳化將這個時間設定為3s(可配置),如果24小時內(可配置)首次超過3s沒有收到pong報文,就將節點置為pfail狀態。如果24小時內頻繁出現,那可能是網路抖動造成,還走原來的路徑等待node_timeout。

  • 減少PFAIL到FAIL的判定時間:只有一個節點收到叢集1/2的節點的PFAIL資訊的時候,才會將故障節點判定為FAIL狀態。而PFAIL這個資訊是透過Gossip協議互動的,最久需要1/2 node_timeout才會通知到其他節點。因此為了加速PFAIL到FAIL的狀態,所有的節點按照統一的規則選出一個種子節點,PFAIL資訊除了隨機傳送一個節點意外,還會通知這個種子節點。這樣種子節點能在最快的時間學習到叢集所有節點的PFAIL資訊,從而將故障節點標記為FAIL狀態廣播到叢集。


3.3.2. RedKV Server

RedKV Server配置多個IO執行緒同時監聽一個埠來接受連線請求,每個執行緒上的連線數目會隨機均衡。每個執行緒只解析自己連線上的請求,並將解析出的報文透過key掛到對應的請求佇列上,每個佇列由一個Worker執行緒處理。這樣同一個key/同一個slot上的請求都會落到同一根Worker執行緒上處理,避免了對key進行加鎖,減少鎖衝突和執行緒切換。Worker執行緒中會對資料進行重編碼,儲存到Rocksdb本地儲存引擎。


RedKV內部的執行緒模型如下圖9:


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖9. RedKV Server無鎖執行緒模型


3.3.3. 資料儲存

RedKV當前支援的資料型別有string、hash和zset,資料節點選擇RocksDB[2]作為本地儲存引擎,叢集建立時支援配置多副本,主從節點離散部署。採用hash打散的方式儲存連續slot分片的資料,能比較好的避免熱點key問題。不同的資料型別包含(MetaKey,MetaValue) 和(DataKey, DataValue),設計格式如下:


MetaKey:

小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


MetaValue:

小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


DataKey:

小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


DataValue:

小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


在如上的編碼方式下,key的設計中保留的slot資訊,可以在擴縮容的場景中透過slot靈活的做資料遷移。

4

4.1. 資料複製

與傳統解決方案引入同步元件的方式不同,我們快速實現了單向資料同步以及叢集擴容需求,整體架構去除了對第三方元件的依賴,透過擴充套件Redis複製協議實現了RedKV資料節點的直接複製,如圖10。單向複製的限制是擴容需要基於2n做節點同步,擴容完成後後臺任務根據3.3.3中定義的key的分片刪除不是本節點的資料。 


在多活的部署形態下,多雲叢集的一對多的資料複製採用單向複製對主叢集效能侵入較大,因此我們實現了基於中心管控的資料複製策略。該策略支援多個叢集的分片異構部署,透過Checkpoint方式定向同步資料,不再需要額外的後臺任務去做資料淘汰,能很好的支援多對多的多雲叢集資料複製、資料破環和擴縮容。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖10. RedKV的資料複製


4.2. 資料批次匯入

小紅書大量的離線業務資料儲存在S3 Hive中,每天會有部分資料需要增量更新,其他的資料會被淘汰。這類場景有幾個挑戰:

  • 批次匯入:如小紅書的筆記資料,一般需要小時級別甚至天級別的更新,所以業務需要有快捷的批次匯入功能。

  • 快速更新:特徵資料的特點就是資料量特別大,以筆記為例,全量筆記在TB 級別資料量。如果透過 Jedis SDK 寫入,那麼儲存叢集需要支援百萬QPS的機器資源。當下小紅書資料平臺支援業務把資料從hive透過工作流直接匯入RedKV,一般是每天凌晨開始寫資料,等到晚高峰時大量讀取。這種方法實踐下來,經常導致 RedKV叢集的叢集記憶體OOM,影響穩定性。

  • 效能及穩定:資料在匯入的過程中不能影響讀的效能


實現方案如圖11:

  • 自定義獲取叢集檢視和資料編碼的UDTF,支援RedKV1.0的資料格式

  • 將原先的抽資料,編碼,分片和排序整合成一個HiveOperator,執行完成後按指定的OutputFormat輸出SST檔案到一個指定S3目錄

  • 透過Hadoop distcp工具做資料的跨雲傳輸,走離線頻寬不影響線上的讀寫業務

  • RedKV叢集的節點SiderCar作為物件儲存的一個Client,RedKV節點載入本節點的SST並ingest


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖11. 離線資料BulkLoad


4.3. 資料批次匯出

小紅書的業務模型訓練資料透過Hash儲存在RedKV叢集中,業務下游需要對訓練結果進行離線分析,希望RedKV具有和Hive資料流通的能力。RedKV本身是不支援Schema的,如果要將KV資料匯入Hive表,則需要將Hash的KKV資料轉化為一個Table。


RedKV的內部資料按hash打散,匯入Hive表則需要提供table關鍵字,先按字首掃描的方式掃描儲存節點,再生成Hive識別的檔案,最後透過Hive Load進行載入。為了更好的相容其他spark任務,我們選擇Hive支援的標準parquet列式儲存檔案,整個I/O鏈路如下圖12:


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖12. RedKV2Hive I/O


示例:RedKV裡面的Key 寫入規定以 {tablename}_ 開始,比如一個artical表


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


RedKV中的資料採用hmset寫入:



hmset {person}_1 name John quantity 20 price 200.23hmset {person}_2 name Henry quantity 30 price 3000.45


透過以上的寫入方式,可以透過配置RedKV2Hive 將KV裡面的資料匯入到Hive裡面的Person表 如果單表的資料量很大,可以採用分表寫入,比如把person表分成16份





hmset {person:1}_1 name John quantity 20 price 200.23hmset {person:1}_2 name Henry quantity 30 price 3000.45...hmset {person:16}_100000 name Tom quantity 43 price 234.56


4.4. 資料的備份和恢復

小紅書的廣告資料儲存在自研的分散式KV系統中,資料安全主要面臨如下挑戰:

  • 基於LSM結構的KV系統,資料compaction導致的空間放大會翻倍,資料量大後,資料備份需要大容量的磁碟

  • 單叢集故障後,叢集恢復的時間不可控

  • 備份資料依賴第三方系統

  • 廣告系統對資料的及時恢復能力有比較高的要求,通常要求在分鐘級。為了解決上述幾個問題,我們提出了一種中心管控的主備叢集容災策略,透過Proxy接入層的秒級切換能快速切流到一個特定的版本


實現方案如圖13:

  • 先部署一個容災叢集,主叢集對外提供讀寫服務,災備叢集儲存特定數量的快照資料

  • 低峰期,中心管控根據配置的版本數和任務時間會定時的向主叢集傳送打快照的服務

  • 快照完成後透過發生遠端rsync命令將快照目錄傳送到容災叢集,主叢集低峰期資料壓縮後資料量可控,這樣災備叢集可以備份指定數量的版本資訊

  • 故障發生後,中心管控可以在災備叢集透過RPC指令指定恢復到一個特定的版本

  • Proxy接入層透過服務註冊與發現主鍵配置2組服務,透過動態的秒級切換可以將流量打向特定版本的叢集,完成服務訪問的秒級切換


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖13. 叢集備份


4.5. 跨雲多活

為了應對高速增長的業務需求,公司對雲廠商的服務穩定性要求越來越高,單機房雲服務難以滿足公司穩定性的需求,跨雲多活可以提高服務的穩定性,雙寫雙讀可以實現主備資料中心均對外提供讀寫服務, 這樣既不會造成資料中心的資源浪費又可以實現跨地域容災。我們對業界常用的方案做了一些對比分析:


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活


我們綜合調研其他廠商的架構經驗,提出了RedKV雙活設計( Replicator as Sidecar Service同機部署) 方案,如圖14。

  • 同機部署,網路開銷小;

  • Sidecar Service 對主服務侵入性小;

  • 單獨部署,易於升級


架構靈活,適合日誌類儲存系統雙活架構。Redis 以及圖資料庫的多雲方案都可以改造適用,具體的功能元件和實戰場景會在後續技術文章詳細介紹。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖14. 跨雲多活架構

5

正如第2節描述的小紅書業務需求場景,本節透過一個典型的業務場景來展示RedKV在noSQL儲存下的收益。


早期在沒有zprofile中臺的場景下,zprofile使用者和筆記資訊都儲存在HBase。為了保證叢集的資料安全和服務穩定性,HBase採用了雙叢集部署,寫入和讀取方透過HBase Client API做資料儲存。HBase的使用者資料在數十TB,在百萬QPS下,P99時延已經在70ms左右,隨著QPS的快速增長,時延越來越高,叢集擴容帶來的儲存成本也越來越高,穩定性保障也面臨極大的挑戰。


RedKV1.0上線後,經過半年多的打磨,開始慢慢承接公司的核心業務。推薦平臺架構組也開始著手打造zprofile中臺服務,收斂上下游的業務,提供標準統一的讀寫方式。在儲存方案上,平臺架構組同學和儲存組經過多次的業務溝通,最終選擇使用RedKV作為底層儲存,主要對接兩類業務方:分別是資料生產者 producer 以及資料消費方 consumer。zprofile最終的中臺架構如下圖15:

  • zprofile-write service 對上游提供統一的資料寫入介面服務,提供使用者和比較的Meta管理,使用者資料寫入redkv-zprofile-user叢集,筆記及其他資料寫入redkv-zprofile-other叢集。

  • zprofile-service對下游提供統一的資料消費服務,對應時延要求不高的離線服務,RedKV本身支援單向資料複製的能力透過2個offline小叢集提供資料scan業務。


整體架構改造完成後,使用RedKV對接同樣QPS的業務能力,成本節省了36%, P99效能提升了約5倍。


小紅書自研KV儲存架構如何實現萬億量級儲存與跨雲多活

圖15. zprofile中臺

6

[1] Pinterest 資料複製:


[2] Rocskdb: 


[3] HeavyKeeper:

 HeavyKeeper: An Accurate Algorithm for Finding Top-k Elephant Flows | USENIX



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2925157/,如需轉載,請註明出處,否則將追究法律責任。

相關文章