美團萬億級 KV 存儲架構與實踐

KV 存儲做爲美團一項重要的在線存儲服務,承載了在線服務天天萬億級的請求量。在 2019 年 QCon 全球軟件開發大會(上海站)上,美團高級技術專家齊澤斌分享了《美團點評萬億級 KV 存儲架構與實踐》,本文系演講內容的整理,主要分爲四個部分:第一部分講述了美團 KV 存儲的發展歷程;第二部分闡述了內存 KV Squirrel 架構和實踐;第三部分介紹了持久化 KV Cellar 架構和實踐;最後分享了將來的發展規劃和業界新趨勢。算法

美團點評 KV 存儲發展歷程

美團第一代的分佈式 KV 存儲以下圖左側的架構所示,相信不少公司都經歷過這個階段。在客戶端內作一致性哈希,在後端部署不少的 Memcached 實例,這樣就實現了最基本的 KV 存儲分佈式設計。但這樣的設計存在很明顯的問題:好比在宕機摘除節點時,會丟數據,緩存空間不夠須要擴容,一致性哈希也會丟失一些數據等等,這樣會給業務開發帶來的不少困擾。後端

隨着 Redis 項目的成熟,美團也引入了 Redis 來解決咱們上面提到的問題,進而演進出來如上圖右側這樣一個架構。你們能夠看到,客戶端仍是同樣,採用了一致性哈希算法,服務器端變成了 Redis 組成的主從結構。當任何一個節點宕機,咱們能夠經過 Redis 哨兵完成 Failover,實現高可用。但有一個問題仍是沒有解決,若是擴縮容的話,一致性哈希仍然會丟數據,那麼這個問題該如何解決呢?緩存

這個時候,咱們發現有了一個比較成熟的 KV 存儲開源項目:阿里 Tair 。2014年,咱們引入了 Tair 來知足業務 KV 存儲方面的需求。Tair 開源版本的架構主要分紅三部分:上圖下邊是存儲節點,存儲節點會上報心跳到它的中心節點,中心節點內部有兩個配置管理節點,會監控全部的存儲節點。當有任何存儲節點宕機或者擴容時,它會作集羣拓撲的從新構建。當客戶端啓動時,它會直接從中心節點拉來一個路由表。這個路由表簡單來講就是一個集羣的數據分佈圖,客戶端根據路由表直接去存儲節點讀寫。針對以前 KV 的擴容丟數據問題,它也有數據遷移機制來保證數據的完整性。服務器

可是,咱們在使用的過程當中,還遇到了一些其餘問題,好比中心節點雖然是主備高可用的,但實際上它沒有相似於分佈式仲裁的機制,因此在網絡分割的狀況下,它是有可能發生「腦裂」的,這個也給咱們的業務形成過比較大的影響。另外,在容災擴容時,也遇到過數據遷移影響到業務可用性的問題。另外,咱們以前用過 Redis ,業務會發現 Redis 的數據結構特別豐富,而 Tair 還不支持這些數據結構。雖然咱們用 Tair 解決了一些問題,可是 Tair 也沒法徹底知足業務需求。畢竟,在美團這樣一個業務規模較大和業務複雜度較高的場景下,很難有開源系統能很好地知足咱們的需求。最終,咱們決定在已應用的開源系統之上進行自研。微信

恰好在2015 年, Redis 官方正式發佈了集羣版本 Redis Cluster。因此,咱們緊跟社區步伐,並結合內部需求作了不少開發工做,演進出了全內存、高吞吐、低延遲的 KV 存儲 Squirrel。另外,基於 Tair,咱們還加入了不少自研的功能,演進出持久化、大容量、數據高可靠的 KV 存儲 Cellar 。由於 Tair 的開源版本已經有四五年沒有更新了,因此,Cellar 的迭代徹底靠美團自研,而 Redis 社區一直很活躍。總的來講,Squirrel 的迭代是自研和社區並重,自研功能設計上也會盡可能與官方架構進行兼容。後面你們能夠看到,由於這些不一樣,Cellar 和 Squirrel 在解決一樣的問題時也選取了不一樣的設計方案。網絡

這兩個存儲其實都是 KV 存儲領域不一樣的解決方案。在實際應用上,若是業務的數據量小,對延遲敏感,咱們建議你們用 Squirrel ;若是數據量大,對延遲不是特別敏感,咱們建議用成本更低的 Cellar 。目前這兩套 KV 存儲系統在美團內部天天的調用量均已突破萬億,它們的請求峯值也都突破了每秒億級。數據結構

內存 KV Squirrel 架構和實踐

在開始以前,本文先介紹兩個存儲系統共通的地方。好比分佈式存儲的經典問題:數據是如何分佈的?這個問題在 KV 存儲領域,就是 Key 是怎麼分佈到存儲節點上的。這裏 Squirrel 跟 Cellar 是同樣的。當咱們拿到一個 Key 後,用固定的哈希算法拿到一個哈希值,而後將哈希值對 Slot 數目取模獲得一個Slot id,咱們兩個 KV 如今都是預分片16384個 Slot 。獲得 Slot id 以後,再根據路由表就能查到這個 Slot 存儲在哪一個存儲節點上。這個路由表簡單來講就是一個 Slot 到存儲節點的對照表。多線程

KV 數據分佈介紹

接下來說一下對高可用架構的認知,我的認爲高可用能夠從宏觀和微觀兩個角度來看。從宏觀的角度來看,高可用就是指容災怎麼作。好比說掛掉了一個節點,你該怎麼作?一個機房或者說某個地域的一批機房宕機了,你該怎麼作?而從微觀的角度看,高可用就是怎麼能保證端到端的高成功率。咱們在作一些運維升級或者擴縮容數據遷移的時候,可否作到業務請求的高可用? 本文也會從宏觀和微觀兩個角度來分享美團作的一些高可用工做。架構

Squirrel 架構

上圖就是咱們的 Squirrel 架構。中間部分跟 Redis 官方集羣是一致的。它有主從的結構, Redis 實例之間經過 Gossip 協議去通訊。咱們在右邊添加了一個集羣調度平臺,包含調度服務、擴縮容服務和高可用服務等,它會去管理整個集羣,把管理結果做爲元數據更新到 ZooKeeper。咱們的客戶端會訂閱 ZooKeeper 上的元數據變動,實時獲取到集羣的拓撲狀態,直接在 Redis 集羣進行讀寫操做。併發

Squirrel 節點容災

而後再看一下 Squirrel 容災怎麼作。對於 Redis 集羣而言,節點宕機已經有完備的處理機制了。官方提供的方案,任何一個節點從宕機到被標記爲 FAIL 摘除,通常須要通過 30 秒。主庫的摘除可能會影響數據的完整性,因此,咱們須要謹慎一些。可是對於從庫呢?咱們認爲這個過程徹底不必。另外一點,咱們都知道內存的 KV 存儲數據量通常都比較小。對於業務量很大的公司來講,它每每會有不少的集羣。若是發生交換機故障,會影響到不少的集羣,宕機以後去補副本就會變得很是麻煩。爲了解決這兩個問題,咱們作了 HA 高可用服務。

它的架構以下圖所示,它會實時監控集羣的全部節點。無論是網絡抖動,仍是發生了宕機(好比說 Redis 2 ),它能夠實時更新 ZooKeeper ,告訴 ZooKeeper 去摘除 Redis 2 ,客戶端收到消息後,讀流量就直接路由到 Redis 3上。若是 Redis 2 只是幾十秒的網絡抖動,過幾十秒以後,若是 HA 節點監控到它恢復後,會把它從新加回。

Squirrel—節點容災

若是過了一段時間,HA 判斷它屬於一個永久性的宕機,HA 節點會直接從 Kubernetes 集羣申請一個新的 Redis 4 容器實例,把它加到集羣裏。此時,拓撲結構又變成了一主兩從的標準結構,HA 節點更新完集羣拓撲以後,就會去寫 ZooKeeper 通知客戶端去更新路由,客戶端就能到 Redis 4 這個新從庫上進行讀操做。

經過上述方案,咱們把從庫的摘除時間從 30 秒下降到了 5 秒。另外,咱們經過 HA 自動申請容器實例加入集羣的方式,把宕機補副本變成了一個分鐘級的自動操做,不須要任何人工的介入。

Squirrel 跨地域容災

咱們解決了單節點宕機的問題,那麼跨地域問題如何解決呢?咱們首先來看下跨地域有什麼不一樣。第一,相對於同地域機房間的網絡而言,跨地域專線很不穩定;第二,跨地域專線的帶寬是很是有限且昂貴的。而集羣內的複製沒有考慮極端的網絡環境。假如咱們把主庫部署到北京,兩個從庫部署在上海,一樣一份數據要在北上專線傳輸兩次,這樣會形成巨大的專線帶寬浪費。另外,隨着業務的發展和演進,咱們也在作單元化部署和異地多活架構。用官方的主從同步,知足不了咱們的這些需求。基於此,咱們又作了集羣間的複製方案。

如上圖所示,這裏畫出了北京的主集羣以及上海的從集羣,咱們要作的是經過集羣同步服務,把北京主集羣的數據同步到上海從集羣上。按照流程,首先要向咱們的同步調度模塊下發「在兩個集羣間創建同步鏈路」的任務,同步調度模塊會根據主從集羣的拓撲結構,把主從集羣間的同步任務下發到同步集羣,同步集羣收到同步任務後會扮成 Redis 的 Slave,經過 Redis 的複製協議,從主集羣上的從庫拉取數據,包括 RDB以及後續的增量變動。同步機收到數據後會把它轉成客戶端的寫命令,寫到上海從集羣的主節點裏。經過這樣的方式,咱們把北京主集羣的數據同步到了上海的從集羣。一樣的,咱們要作異地多活也很簡單,再加一個反向的同步鏈路,就能夠實現集羣間的雙向同步。

接下來咱們講一下如何作好微觀角度的高可用,也就是保持端到端的高成功率。對於 Squirrel ,主要講以下三個影響成功率的問題:

  • 數據遷移形成超時抖動。
  • 持久化形成超時抖動。
  • 熱點 Key 請求致使單節點過載。

Squirrel 智能遷移

對於數據遷移,咱們主要遇到三個問題:

  • Redis Cluster 雖然提供了數據遷移能力,可是對於要遷哪些 Slot,Slot 從哪遷到哪,它並無論。
  • 作數據遷移的時候,你們都想越快越好,可是遷移速度過快又可能影響業務正常請求。
  • Redis 的 Migrate 命令會阻塞工做線程,尤爲在遷移大 Value 的時候會阻塞特別久。

爲了解決這些問題,咱們作了全新的遷移服務。

下面咱們按照工做流,講一下它是如何運行的。首先生成遷移任務,這步的核心是「就近原則」,好比說同機房的兩個節點作遷移確定比跨機房的兩個節點快。遷移任務生成以後,會把任務下發到一批遷移機上。遷移機遷移的時候,有這樣幾個特色:

  • 第一,會在集羣內遷出節點間作併發,好比同時給 Redis 一、Redis 3 下發遷移命令。
  • 第二,每一個 Migrate 命令會遷移一批 Key。
  • 第三,咱們會用監控服務去實時採集客戶端的成功率、耗時,服務端的負載、QPS 等,以後把這個狀態反饋到遷移機上。遷移數據的過程就相似 TCP 慢啓動的過程,它會把速度一直往上加,若出現請求成功率降低等狀況,它的速度就會下降,最終遷移速度會在動態平衡中穩定下來,這樣就達到了最快速的遷移,同時又儘量小地影響業務的正常請求。

接下來,咱們看一下大 Value 的遷移,咱們實現了一個異步 Migrate 命令,該命令執行時,Redis 的主線程會繼續處理其餘的正常請求。若是此時有對正在遷移 Key 的寫請求過來,Redis 會直接返回錯誤。這樣最大限度保證了業務請求的正常處理,同時又不會阻塞主線程。

Squirrel 持久化重構

Redis 主從同步時會生成 RDB。生成 RDB 的過程會調用 Fork 產生一個子進程去寫數據到硬盤,Fork 雖然有操做系統的 COW 機制,可是當內存用量達到 10 G 或 20 G 時,依然會形成整個進程接近秒級的阻塞。這對在線業務來講幾乎是沒法接受的。咱們也會爲數據可靠性要求高的業務去開啓 AOF,而開 AOF 就可能因 IO 抖動形成進程阻塞,這也會影響請求成功率。對官方持久化機制的這兩個問題,咱們的解決方案是重構持久化機制。

上圖是咱們最新版的 Redis 持久化機制,寫請求會先寫到 DB 裏,而後寫到內存 Backlog,這跟官方是同樣的。同時它會把請求發給異步線程,異步線程負責把變動刷到硬盤的 Backlog 裏。當硬盤 Backlog 過多時,咱們會主動在業務低峯期作一次 RDB ,而後把 RDB 以前生成的 Backlog 刪除。

若是這時候咱們要作主從同步,去尋找同步點的時候,該怎麼辦?第一步仍是跟官方同樣,咱們會從內存 Backlog 裏找有沒有要求的同步點,若是沒有,咱們會去硬盤 Backlog 找同步點。因爲硬盤空間很大,硬盤 Backlog 能夠存儲特別多的數據,因此不多會出現找不到同步點的狀況。若是硬盤 Backlog 也沒有,咱們就會觸發一次相似於全量重傳的操做,但這裏的全量重傳是不須要當場生成 RDB 的,它能夠直接用硬盤已存的 RDB 及其以後的硬盤 Backlog 完成全量重傳。經過這個設計,咱們減小了不少的全量重傳。另外,咱們經過控制在低峯區生成 RDB ,減小了不少 RDB 形成的抖動。同時,咱們也避免了寫 AOF 形成的抖動。不過,這個方案由於寫 AOF 是徹底異步的,因此會比官方的數據可靠性差一些,但咱們認爲這個代價換來了可用性的提高,這是很是值得的。

Squirrel 熱點 Key

下面看一下 Squirrel 的熱點 Key 解決方案。以下圖所示,普通主、從是一個正常集羣中的節點,熱點主、從是遊離於正常集羣以外的節點。咱們看一下它們之間怎麼發生聯繫。

當有請求進來讀寫普通節點時,節點內會同時作請求 Key 的統計。若是某個 Key 達到了必定的訪問量或者帶寬的佔用量,會自動觸發流控以限制熱點 Key 訪問,防止節點被熱點請求打滿。同時,監控服務會週期性的去全部 Redis 實例上查詢統計到的熱點 Key。若是有熱點,監控服務會把熱點 Key 所在 Slot 上報到咱們的遷移服務。遷移服務這時會把熱點主從節點加入到這個集羣中,而後把熱點 Slot 遷移到這個熱點主從上。由於熱點主從上只有熱點 Slot 的請求,因此熱點 Key的處理能力獲得了大幅提高。經過這樣的設計,咱們能夠作到實時的熱點監控,並及時經過流控去止損;經過熱點遷移,咱們能作到自動的熱點隔離和快速的容量擴充。

持久化 KV Cellar 架構和實踐

下面看一下持久化 KV Cellar 的架構和實踐。下圖是咱們最新的 Cellar 架構圖。

跟阿里開源的 Tair 主要有兩個架構上的不一樣。第一個是OB,第二個是 ZooKeeper。咱們的 OB 跟 ZooKeeper 的 Observer 是相似的做用,提供 Cellar 中心節點元數據的查詢服務。它能夠實時與中心節點的 Master 同步最新的路由表,客戶端的路由表都是從 OB 去拿。 這樣作的好處主要有兩點,第一,把大量的業務客戶端跟集羣的大腦 Master 作了自然的隔離,防止路由表請求影響集羣的管理。第二,由於 OB 只供路由表查詢,不參與集羣的管理,因此它能夠進行水平擴展,極大地提高了咱們路由表的查詢能力。另外,咱們引入了 ZooKeeper 作分佈式仲裁,解決我剛纔提到的 Master、Slave 在網絡分割狀況下的「腦裂」問題,而且經過把集羣的元數據存儲到 ZooKeeper,咱們保證了元數據的高可靠。

Cellar 節點容災

介紹完總體的架構,咱們看一下 Cellar 怎麼作節點容災。一個集羣節點的宕機通常是臨時的,一個節點的網絡抖動也是臨時的,它們會很快地恢復,並從新加入集羣。由於節點的臨時離開就把它完全摘除,並作數據副本補全操做,會消耗大量資源,進而影響到業務請求。因此,咱們實現了 Handoff 機制來解決這種節點短時故障帶來的影響。

如上圖所示 ,若是 A 節點宕機了,會觸發 Handoff 機制,這時候中心節點會通知客戶端 A節點發生了故障,讓客戶端把分片 1 的請求也打到 B 上。B 節點正常處理完客戶端的讀寫請求以後,還會把本應該寫入 A 節點的分片 1&2 數據寫入到本地的 Log 中。

若是 A 節點宕機後 3~5 分鐘,或者網絡抖動 30~50 秒以後恢復了,A 節點就會上報心跳到中心節點,中心節點就會通知 B 節點:「 A 節點恢復了,你去把它不在期間的數據傳給它。」這時候,B 節點就會把本地存儲的 Log 回寫到 A 節點上。等到 A 節點擁有了故障期間的全量數據以後,中心節點就會告訴客戶端,A 節點已經完全恢復了,客戶端就能夠從新把分片 1 的請求打回 A 節點。

經過這樣的操做,咱們能夠作到秒級的快速節點摘除,並且節點恢復後加回,只需補齊少許的增量數據。另外若是 A 節點要作升級,中心節點先經過主動 Handoff 把 A 節點流量切到 B 節點,A 升級後再回寫增量 Log,而後切迴流量加入集羣。這樣經過主動觸發 Handoff 機制,咱們就實現了靜默升級的功能。

Cellar 跨地域容災

下面我介紹一下 Cellar 跨地域容災是怎麼作的。Cellar 跟 Squirrel 面對的跨地域容災問題是同樣的,解決方案一樣也是集羣間複製。如下圖一個北京主集羣、上海從集羣的跨地域場景爲例,好比說客戶端的寫操做到了北京的主集羣 A 節點,A 節點會像正常集羣內複製同樣,把它複製到 B 和 D 節點上。同時 A 節點還會把數據複製一份到從集羣的 H 節點。H 節點處理完集羣間複製寫入以後,它也會作從集羣內的複製,把這個寫操做複製到從集羣的 I 、K 節點上。經過在主從集羣的節點間創建這樣一個複製鏈路,咱們完成了集羣間的數據複製,而且這個複製保證了最低的跨地域帶寬佔用。一樣的,集羣間的兩個節點經過配置兩個雙向複製的鏈路,就能夠達到雙向同步異地多活的效果。

Cellar 強一致

咱們作好了節點容災以及跨地域容災後,業務又對咱們提出了更高要求:強一致存儲。咱們以前的數據複製是異步的,在作故障摘除時,可能由於故障節點數據還沒複製出來,致使數據丟失。可是對於金融支付等場景來講,它們是不允許數據丟失的。面對這個難題,咱們該怎麼解決?目前業界主流的解決方案是基於 Paxos 或 Raft 協議的強一致複製。咱們最終選擇了 Raft 協議。主要是由於 Raft 論文是很是詳實的,是一篇工程化程度很高的論文。業界也有很多比較成熟的 Raft 開源實現,能夠做爲咱們研發的基礎,進而可以縮短研發週期。

下圖是如今 Cellar 集羣 Raft 複製模式下的架構圖,中心節點會作 Raft 組的調度,它會決定每個 Slot 的三副本存在哪些節點上。

你們能夠看到 Slot 1 在存儲節點 一、二、4 上,Slot 2 在存儲節點二、三、4上。每一個 Slot 組成一個 Raft 組,客戶端會去 Raft Leader 上進行讀寫。因爲咱們是預分配了 16384 個 Slot,因此,在集羣規模很小的時候,咱們的存儲節點上可能會有數百甚至上千個 Slot 。這時候若是每一個 Raft 複製組都有本身的複製線程、 複製請求和 Log等,那麼資源消耗會很是大,寫入性能會不好。因此咱們作了 Multi Raft 實現, Cellar 會把同一個節點上全部的 Raft 複製組寫一份 Log,用同一組線程去作複製,不一樣 Raft 組間的複製包也會按照目標節點作整合,以保證寫入性能不會因 Raft 組過多而變差。 Raft 內部實際上是有本身的選主機制,它能夠控制本身的主節點,若是有任何節點宕機,它能夠經過選舉機制選出新的主節點。那麼,中心節點是否是就不須要管理 Raft 組了嗎?不是的。這裏講一個典型的場景,若是一個集羣的部分節點通過幾輪宕機恢復的過程, Raft Leader 在存儲節點之間會變得極其不均。而爲了保證數據的強一致,客戶端的讀寫流量又必須發到 Raft Leader,這時候集羣的節點流量會很不均衡。因此咱們的中心節點還會作 Raft 組的 Leader 調度。好比說 Slot 1 存儲在節點 一、二、4,而且節點 1 是 Leader。若是節點 1 掛了,Raft 把節點 2 選成了 Leader。而後節點 1 恢復了並從新加入集羣,中心節點這時會讓節點 2 把 Leader 還給節點 1 。這樣,即使通過一系列宕機和恢復,咱們存儲節點之間的 Leader 數目仍然能保證是均衡的。

接下來,咱們看一下 Cellar 如何保證它的端到端高成功率。這裏也講三個影響成功率的問題。Cellar 遇到的數據遷移和熱點 Key 問題與 Squirrel 是同樣的,但解決方案不同。這是由於 Cellar 走的是自研路徑,不用考慮與官方版本的兼容性,對架構改動更大些。另外一個問題是慢請求阻塞服務隊列致使大面積超時,這是 Cellar 網絡、工做多線程模型設計下會遇到的不一樣問題。

Cellar 智能遷移

上圖是 Cellar 智能遷移架構圖。咱們把桶的遷移分紅了三個狀態。第一個狀態就是正常的狀態,沒有任何遷移。若是這時候要把 Slot 2 從 A 節點遷移到 B節點,A 會給 Slot 2 打一個快照,而後把這個快照全量發到 B 節點上。在遷移數據的時候, B 節點的回包會帶回 B 節點的狀態。B 的狀態包括什麼?引擎的壓力、網卡流量、隊列長度等。A 節點會根據 B 節點的狀態調整本身的遷移速度。像 Squirrel 同樣,它通過一段時間調整後,遷移速度會達到一個動態平衡,達到最快速的遷移,同時又儘量小地影響業務的正常請求。

當 Slot 2 遷移完後, 會進入圖中 Slot 3 的狀態。客戶端這時可能還沒更新路由表,當它請求到了 A 節點,A 節點會發現客戶端請求錯了節點,但它不會返回錯誤,它會把請求代理到 B 節點上,而後把 B 的響應包再返回客戶端。同時它會告訴客戶端,須要更新一下路由表了,此後客戶端就能直接訪問到 B 節點。這樣就解決了客戶端路由更新延遲形成的請求錯誤。

Cellar 快慢列隊

下圖上方是一個標準的線程隊列模型。網絡線程池接收網絡流量解析出請求包,而後把請求放到工做隊列裏,工做線程池會從工做隊列取請求來處理,而後把響應包放回網絡線程池發出。

咱們分析線上發生的超時案例時發現,一批超時請求當中每每只有一兩個請求是引擎處理慢致使的,大部分請求,只是由於在隊列等待太久致使總體響應時間過長而超時了。從線上分析來看,真正的慢請求佔超時請求的比例只有 1/20。

咱們的解法是什麼樣?很簡單,拆線程池、拆隊列。咱們的網絡線程在收到包以後,會根據它的請求特色,是讀仍是寫,快仍是慢,分到四個隊列裏。讀寫請求比較好區分,但快慢怎麼分開?咱們會根據請求的 Key 個數、Value大小、數據結構元素數等對請求進行快慢區分。而後用對應的四個工做線程池處理對應隊列的請求,就實現了快慢讀寫請求的隔離。這樣若是我有一個讀的慢請求,不會影響另外三種請求的正常處理。不過這樣也會帶來一個問題,咱們的線程池從一個變成四個,那線程數是否是變成原來的四倍?其實並非的,咱們某個線程池空閒的時候會去幫助其它的線程池處理請求。因此,咱們線程池變成了四個,可是線程總數並無變。咱們線上驗證中這樣的設計能把服務 TP999 的延遲下降 86%,可大幅下降超時率。

Cellar 熱點 Key

上圖是 Cellar 熱點 Key 解決方案的架構圖。咱們能夠看到中心節點加了一個職責,多了熱點區域管理,它如今不僅負責正常的數據副本分佈,還要管理熱點數據的分佈,圖示這個集羣在節點 C、D 放了熱點區域。咱們經過讀寫流程看一下這個方案是怎麼運轉的。若是客戶端有一個寫操做到了 A 節點,A 節點處理完成後,會根據實時的熱點統計結果判斷寫入的 Key 是否爲熱點。若是這個 Key 是一個熱點,那麼它會在作集羣內複製的同時,還會把這個數據複製有熱點區域的節點,也就是圖中的 C、D 節點。同時,存儲節點在返回結果給客戶端時,會告訴客戶端,這個 Key 是熱點,這時客戶端內會緩存這個熱點 Key。當客戶端有這個 Key 的讀請求時,它就會直接去熱點區域作數據的讀取。經過這樣的方式,咱們能夠作到只對熱點數據作擴容,不像 Squirrel ,要把整個 Slot 遷出來作擴容。有必要的話,中心節點也能夠把熱點區域放到集羣的全部節點上,全部的熱點讀請求就能均衡的分到全部節點上。另外,經過這種實時的熱點數據複製,咱們很好地解決了相似客戶端緩存熱點 KV 方案形成的一致性問題。

發展規劃和業界趨勢

最後,一塊兒來看看咱們項目的規劃和業界的技術趨勢。這部份內容會按照服務、系統、硬件三層來進行闡述。首先在服務層,主要有三點:

  • 第一,Redis Gossip 協議優化。你們都知道 Gossip 協議在集羣的規模變大以後,消息量會劇增,它的 Failover 時間也會變得愈來愈長。因此當集羣規模達到 TB 級後,集羣的可用性會受到很大的影響,因此咱們後面會重點在這方面作一些優化。
  • 第二,咱們已經在 Cellar 存儲節點的數據副本間作了 Raft 複製,能夠保證數據強一致,後面咱們會在 Cellar 的中心點內部也作一個 Raft 複製,這樣就不用依賴於 ZooKeeper 作分佈式仲裁、元數據存儲了,咱們的架構也會變得更加簡單、可靠。
  • 第三,Squirrel 和 Cellar 雖然都是 KV 存儲,可是由於它們是基於不一樣的開源項目研發的,因此 API 和訪問協議不一樣,咱們以後會考慮將 Squirrel 和 Cellar 在 SDK 層作整合,雖而後端會有不一樣的存儲集羣,但業務側能夠用一套 SDK 進行訪問。

在系統層面,咱們正在調研並去落地一些 Kernel Bypass 技術,像 DPDK、SPDK 這種網絡和硬盤的用戶態 IO 技術。它能夠繞過內核,經過輪詢機制訪問這些設備,能夠極大提高系統的 IO 能力。存儲做爲 IO 密集型服務,性能會得到大幅的提高。

在硬件層面,像支持 RDMA 的智能網卡能大幅下降網絡延遲和提高吞吐;還有像 3D XPoint 這樣的閃存技術,好比英特爾新發布的 AEP 存儲,其訪問延遲已經比較接近內存了,之後閃存跟內存之間的界限也會變得愈來愈模糊;最後,看一下計算型硬件,好比經過在閃存上加 FPGA 卡,把本來應該 CPU 作的工做,像數據壓縮、解壓等,下沉到卡上執行,這種硬件能在解放 CPU 的同時,也能夠下降服務的響應延遲。

做者簡介

澤斌,美團點評高級技術專家,2014 年加入美團。

招聘信息

美團基礎技術部存儲技術中心長期招聘 C/C++、Go、Java 高級/資深工程師和技術專家,歡迎加入美團基礎技術部你們庭。歡迎感興趣的同窗發送簡歷至:tech@meituan.com(郵件標題註明:基礎技術部-存儲技術中心)

閱讀更多技術文章,請掃碼關注微信公衆號-美團技術團隊!

相關文章
相關標籤/搜索