2.1?Squirrel 節(jié)點容災????2.2?跨地域容災????2.3?智能遷移 ? 2.4?持久化重構??2.5?熱點 Key
3.1節(jié)點容災??3.2跨地域容災? 3.3強一致????3.4智能遷移????3.5快慢列隊????3.6熱點 Key
一、美團點評 KV 存儲發(fā)展歷程
1.1第一代(左側)
客戶端內做一致性哈希,后端部署很多Memcached實例,實現最基本 KV 存儲分布式設計。
問題:宕機摘除節(jié)點/擴容,一致性哈希丟數據
1.2第二代(右側)
客戶端同上,服務器Redis組成的主從結構。
問題:哨兵完成 Failover,實現高可用。但擴縮容,一致性哈希仍丟數據


1.3第三代
這時發(fā)現成熟KV 存儲開源項目:阿里 Tair。
開源版本架構主要分成三部分:
1)存儲節(jié)點:上報心跳到它的中心節(jié)點
2)中心節(jié)點:兩個配置管理節(jié)點,會監(jiān)控所有的存儲節(jié)點,宕機或者擴容時,集群拓撲重新構建
3)客戶端:啟動時,直接從中心節(jié)點拉路由表。根據路由表(集群數據分布圖)直接讀寫存儲節(jié)點。有數據遷移機制保證數據完整性。
使用遇到問題:Tair 解決了一些問題,但無法完全滿足
1)沒有仲裁,網絡分割有可能發(fā)生“腦裂”的,給業(yè)務造成過較大影響。
2)容災擴容時,數據遷移影響到業(yè)務可用性
3)Redis數據結構特別豐富,Tair 還不支持

1.4自研
Squirrel:基于Redis Cluster(2015 年發(fā)布),演進出全內存、高吞吐、低延遲的 KV 存儲。
迭代:自研和社區(qū)并重,盡量兼容官方。
應用:數據量小,對延遲敏感
Cellar:基于 Tair,演進出持久化、大容量、數據高可靠KV 存儲。
迭代:完全靠自研(四五年沒更新)。和 Squirrel 在解決同樣的問題時也選取了不同的設計方案。
應用:數據量大,對延遲不特別敏感
目前美團內部每天的調用量均已突破萬億,請求峰值突破每秒億級
二、內存 KV Squirrel 架構和實踐
共通:數據分布一樣(Key怎么分布到存儲節(jié)點上)。拿Key 哈希到哈希值,哈希值對 Slot 數取模得Slot id,都是預分片16384個Slot。路由表就是一個 Slot 到存儲節(jié)點對照表

Squirrel 架構:
集群跟Redis一致(中間):主從,通過Gossip 協(xié)議去通信。
添加集群調度平臺(右):調度服務、擴縮容服務和高可用服務等,管理整個集群,把結果作為元數據更新到zk??蛻舳藭嗛唞k元數據變更,實時獲取到集群拓撲狀態(tài),直接讀寫Redis集群

2.1 Squirrel 節(jié)點容災
1)Redis集群節(jié)點宕機已有完備處理機制:從宕機到被標記為 FAIL 摘除,一般30秒。主庫摘除可能影響數據完整性,謹慎一些。但從庫,我們認為這個過程完全沒必要。
2)內存KV 存儲數據量一般比較小。業(yè)務量大公司,會有很多集群。如交換機故障,影響很多集群,宕機補副本非常麻煩。
我們做了 HA 高可用服務,解決這兩個問題:1)從庫摘除時間從?30 秒降到5 秒。2)通過 HA 自動申請容器實例加入集群的方式,把宕機補副本變成分鐘級自動操作,不需人工介入
實時監(jiān)控集群的所有節(jié)點。網絡抖動/宕機(比如說Redis2 )實時更新zk,去摘除Redis 2:1)客戶端收到消息后,讀流量就直接路由到Redis3上。
2)如只是幾十秒的網絡抖動, HA 節(jié)點監(jiān)控到恢復后,重新加回

3)如HA 判斷屬于永久性宕機,HA 節(jié)點會直接從 Kubernetes 集群申請新的 Redis 4 容器實例,加到集群里。拓撲結構又變成一主兩從,HA 節(jié)點更新完集群拓撲之后,寫 ZK通知客戶端去更新路由,客戶端就能讀新從庫?Redis 4?

2.2 Squirrel 跨地域容災
1、跨地域于單節(jié)點不同:
1)跨地域專線不穩(wěn)定,相對于同地域機房間網絡;
2)帶寬有限且昂貴,同樣一份數據要傳輸兩次,巨大帶寬浪費
3)官方主從同步滿足不了,單元化部署和異地多活架構。基于此,我們做了集群間復制方案
2、下圖:北京主集群、上海從集群,把北京數據同步上海:
1)向同步調度模塊,下發(fā)“建立同步鏈路”任務,
2)同步調度模塊,根據集群結構,把任務下發(fā)到同步集群,
3)同步集群收到,扮成 Redis 的 Slave,通過 Redis 復制協(xié)議,從主集群上的從庫拉數據,包括 RDB及后續(xù)增量變更
4)同步機收到數據后,把它轉成客戶端寫命令,寫上海從集群主節(jié)點里。
ps:同樣,異地多活,再加一個反向同步鏈路,實現集群雙向同步
如何做好微觀角度高可用,保持端到端的高成功率。 Squirrel 三個影響成功率的問題:
1)數據遷移造成超時抖動
2)持久化造成超時抖動
3)熱點 Key 請求導致單節(jié)點過載

2.3?Squirrel 智能遷移
數據遷移三個問題:
1)Redis Cluster 雖能遷移,但不管要遷哪些 Slot,從哪遷到哪
2)想越快越好,但遷移過快又可能影響業(yè)務正常請求
3)Redis 的 Migrate 命令會阻塞工作線程,尤其遷移大 Value 時候會阻塞特別久
解決這些問題,做新的遷移服務
1)生成遷移任務,的核心是“就近原則”,同機房遷移肯定比跨機房快。
2)任務生成后,下發(fā)任務到一批遷移機上
? ? ? ? 遷移機遷移時特點:
????????1.并發(fā),同時給 Redis 1、Redis 3 下發(fā)遷移命令
? ? ? ? 2.每個 Migrate 命令會遷移一批 Key
? ? ? ? 3.監(jiān)控實時采集客戶端成功率、耗時,服務端負載、QPS 等,把狀態(tài)反饋到遷移機。
? ? ? ? 4.遷移過程類似 TCP 慢啟動,速度一直加,若請求成功率下降,降速度,速度動態(tài)平衡中穩(wěn)定,最快速遷移,最小影響業(yè)務正常請求
3)大 Value 的遷移,異步實現 Migrate 命令,執(zhí)行時,Redis 主線程繼續(xù)處理正常請求。如有遷移請求,直接返回錯誤。保證業(yè)務請求處理,同時不阻塞主線程

2.4 Squirrel 持久化重構
背景:RDB 過程調用 Fork 產生子進程去寫數據到硬盤,雖然有操作系統(tǒng)COW 機制,但內存用量達到 10 /20 G 時,秒級阻塞。在線業(yè)務來無法接受。可靠性要求高業(yè)務開啟 AOF,開 AOF 可能因 IO 抖動進程阻塞,影響請求成功率。
改進:
1)寫時:先寫 DB ,然后寫內存 Backlog,跟官方一樣。同時把請求發(fā)異步線程,把變更刷到硬盤 Backlog 。Backlog 過多,做 RDB(業(yè)務低峰期)?,把 RDB 之前Backlog 刪除。
2)找同步點時
????1.從內存 Backlog 里找,
? ? 2.沒有去硬盤 Backlog 找(由于硬盤空間很大,存儲多,很少會找不到)。
? ? 3.如硬盤 Backlog 沒有,觸發(fā)全量重傳, 直接用硬盤已存RDB 及之后硬盤 Backlog 完成全量重傳。
????優(yōu)點:1.不需當場生成 RDB,減少很多全量重傳
? ? ? ? ? ? ? ?2.控制在低峰區(qū)生成 RDB ,減少RDB 造成的抖動。同時避免了寫 AOF 造成的抖動。ps:寫 AOF 完全異步,比官方可靠性差一些,但可用性提升,非常值得的。

2.5 Squirrel 熱點 Key
解決方案如下圖,普通主、從是正常集群中節(jié)點,熱點主、從游離于正常集群外節(jié)點。它們之間怎么發(fā)生聯(lián)系

實時熱點監(jiān)控,流控止損:? 讀寫普通節(jié)點時,節(jié)點內同時做請求 Key 統(tǒng)計,某Key 達到一定訪問量或者帶寬占用量,自動觸發(fā)流控以限制熱點 Key 訪問,防止節(jié)點被打滿。
自動熱點隔離,遷移和快速擴容:? ??同時,監(jiān)控服務周期性去Redis 實例查統(tǒng)計熱點 Key。把熱點 Key 所在 Slot 上報到遷移服務,把熱點主從節(jié)點加到集群中,熱點 Slot 遷移到這個熱點主從上。因為熱點主從只有熱點 Slot 請求,處理能力大幅提升
三、持久化 KV Cellar 架構和實踐
跟開源Tair兩不同:
OB: 跟 ZooKeeper 的 Observer類似作用,查詢Cellar 中心節(jié)點元數據。與中心節(jié)點 Master 實時同步路由表,客戶端路由表從 OB 拿。
? ??這樣好處:1)把大量的業(yè)務客戶端跟集群的大腦 Master 做了天然的隔離,防止路由表請求影響集群的管理。2)因為 OB 只供路由表查詢,不參與集群的管理,所以它可以進行水平擴展,極大地提升路由表查詢能力
ZK:做分布式仲裁,解決Master、Slave 網絡分割的“腦裂”問題,元數據存zk,保證高可靠

3.1 Cellar 節(jié)點容災
集群節(jié)點宕機、網絡抖動一般是臨時的,很快恢復,重新加入集群。因為臨時離開就徹底摘除,并做數據副本補全,消耗大,影響業(yè)務請求。所以,實現Handoff解決節(jié)點短時故障帶來的影響:
A 宕機觸發(fā) Handoff :1)中心節(jié)點通知客戶端 A故障,2)讓客戶端把分片 1 請求也打到 B 上。3)B 處理完,把應寫入 A的?1&2 數據寫本地 Log 中

A 節(jié)點宕機3~5 分鐘,或網絡抖動 30~50 秒恢復:
1)A 上報心跳到中心節(jié)點,通知 B 節(jié)點 A恢復
2)B把本地 Log 回寫A 上,A 有故障期全量數據后
3)中心節(jié)點告訴客戶端,客戶端重新把分片 1 請求打回 A 節(jié)點


好處:1)秒級摘除,恢復后加回,只需補少量增量數據。
? ? ? ? ? ?2)主動觸發(fā) Handoff 機制,靜默升級:如A 升級,中心節(jié)點通過主動 Handoff 把 A 流量切到 B ,A 升級后回寫增量 Log,切回流量加入集群
3.2 Cellar 跨地域容災
Cellar 跟 Squirrel 跨地域容災問題一樣,解決方案同樣也是集群間復制。
北京主集群、上海從:客戶端寫到北京A 節(jié)點,A 正常集群內復制到 B 和 D ,同時到從的 H。H處理完集群間復制寫,做集群內復制到I 、K 上。保證最低跨地域帶寬占用。集群間兩個節(jié)點雙向復制,達到雙向同步異地多活

3.3 Cellar 強一致
做好節(jié)點及跨地域容災后,業(yè)務提出更高要求:強一致存儲。
之前異步復制數據,故障摘除時,可能故障節(jié)點數據沒復制,導致丟失。支付場景不容許,業(yè)界主流基于 Paxos 或 Raft ,最終選Raft因為:
1)Raft 論文詳實,工程化高
2)業(yè)界不少成熟Raft 開源實現,可作研發(fā)基礎,縮短研發(fā)周期
Cellar 集群 Raft 復制模式架構圖,中心節(jié)點做 Raft 組調度,決定每個 Slot 三副本存在哪些節(jié)點上

Slot 1 在存儲節(jié)點 1、2、4 上,Slot 2 在存儲節(jié)點2、3、4上。
每個 Slot 組成一個 Raft 組,客戶端去 Raft Leader 讀寫。
預分配16384 個 Slot,集群小時,存儲節(jié)點上有數百上千個 Slot 。這時如每個 Raft 復制組都有自己復制線程、請求和 Log等,資源消耗大,寫性能很差
解決:Multi Raft 實現
1)"寫性能"不因 Raft 組過多變差:Cellar 把同一節(jié)點上所有Raft 復制組寫一份 Log,用同一組線程復制,不同 Raft 組間復制包按照目標節(jié)點做整合
2)Raft 任何節(jié)點宕機,都可選舉新主節(jié)點,但中心節(jié)點仍要管理 Raft 組:
例:集群部分節(jié)點幾輪宕機恢復,集群節(jié)點流量很不均衡,因為保證數據強一致,客戶端讀寫流量又必須發(fā)到 Raft Leader
????如:Slot 1 存儲節(jié)點 1、2、4,1 是 Leader掛了, 2 選成了 Leader。1 恢復并重新加入集群,中心節(jié)點這時會讓 2 把 Leader 還給1 。節(jié)點間 Leader 數目均衡
看Cellar 如何保證它端到端高成功率。這里講三個影響成功率問題:
????1、2)Cellar 遇到數據遷移和熱點 Key 問題與 Squirrel 一樣,但解決方案不一樣。因為 Cellar自研,不用考慮與官方版本兼容性,對架構改動更大。
????3)慢請求阻塞服務隊列導致大面積超時,這是 Cellar 網絡、工作多線程模型設計下會遇到不同問題
3.4 Cellar 智能遷移

桶的遷移分三個狀態(tài):
1、正常(不遷移):Slot 2 從 A 遷到 B節(jié)點,A 給2 打快照,把快照全量發(fā)到 B 上。
2、遷移時:B 節(jié)點回包帶回 B 節(jié)點狀態(tài)(引擎的壓力、網卡流量、隊列長度等)。A 根據 B 狀態(tài)調整自己遷移速度。像 Squirrel 一樣,調整后,遷移速度動態(tài)平衡,達最快遷移,同時盡可能小影響業(yè)務正常請求
3、遷移完:進入Slot 3 狀態(tài),客戶端這時可能沒更新路由表,當請求到A 節(jié)點,會代理到 B 上,B 響應包再返回客戶端。同時告訴客戶端,更新路由表,解決客戶端路由更新延遲造成請求錯誤。
3.5 Cellar 快慢列隊
下圖上方:標準線程隊列。網絡線程池接 收?網絡流量?解析出 請求包,把請求放工作隊列,工作線程池會從工作隊列取?請求來?處理,響應包放回 網絡線程池?發(fā)出

一批超時請求:往往只有一兩個是引擎處理慢導致,大部分因為在隊列等待過久。慢只有 1/20
解法:拆線程池、拆隊列。網絡線程在收到包之后,根據請求特點,讀/寫,快/慢,分到四個隊列,互不影響
快慢怎么分開?Key 數、Value大小、數據結構元素區(qū)分
帶來問題,線程池從一變四,線程數變四倍?并不是,空閑時幫其它處理。把服務 TP999 延遲降低 86%,大幅降低超時率
3.6 Cellar 熱點 Key

中心節(jié)點加一職責:管理熱點數據分布,不只負責正常分布
1) C、D 放熱點區(qū)域。通過讀寫看運轉:寫到A ,處理完,根據實時熱點統(tǒng)計結果判斷寫入Key 是否為熱點
2)如是,集群內、熱點區(qū)域C、D 同時復制。返回時告訴客戶端,Key 是熱點,客戶端緩存Key。這樣只對熱點數據做擴容,不像 Squirrel 整個 Slot 遷出做擴容。
3)有必要的話,中心節(jié)點也可把熱點區(qū)域放所有節(jié)點上,熱點讀請求就均衡分。
好處:實時熱點數據復制,解決類似客戶端緩存熱點 KV 方案一致性問題
四、發(fā)展規(guī)劃和業(yè)界趨勢
按照服務、系統(tǒng)、硬件三層闡述。
服務層三點:
1、Redis Gossip 協(xié)議優(yōu)化。Gossip 協(xié)議在集群變大后,消息量劇增,Failover 時間變長。達到 TB 級,集群可用性受很大影響,后面做優(yōu)化
2、已經Cellar 存儲節(jié)點數據副本間做 Raft 復制,保證強一致,后面在中心點內部也做,不依賴zk仲裁、存元數據儲了,架構變簡單、可靠
3、Squirrel 和 Cellar 在 SDK 層做整合:雖都是 KV 存儲,但 API 和訪問協(xié)議不同,后端不同存儲集群,業(yè)務側用一套 SDK 訪問
系統(tǒng)層面
調研并落地Kernel Bypass 技術,像 DPDK、SPDK 網絡和硬盤的用戶態(tài) IO 技術。繞過內核,輪詢訪問這些設備,極大提升系統(tǒng)IO。存儲作為 IO 密集型服務,性能大幅提升。
硬件層面
1、支持 RDMA 智能網卡能大幅降低網絡延遲和提升吞吐;還有像 3D XPoint 這樣的閃存技術,如英特爾新AEP 存儲,訪問延遲接近內存,以后閃存跟內存間的界限變模糊;
2、通過在閃存上加 FPGA 卡,原本CPU 做(數據壓縮、解壓),下沉到卡上執(zhí)行,解放 CPU, 降低響應延遲
https://tech.meituan.com/2020/07/01/kv-squirrel-cellar.html