美團萬億級 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 的時候會阻塞特別久。

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

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

  1. 會在集羣內遷出節點間做併發,比如同時給 Redis 1、Redis 3 下發遷移命令。

  2. 每個 Migrate 命令會遷移一批 Key。

  3. 我們會用監控服務去實時採集客戶端的成功率、耗時,服務端的負載、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 在存儲節點 1、2、4 上,Slot 2 在存儲節點2、3、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 存儲在節點 1、2、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 年加入美團。

----------  END  ----------

招聘信息

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

也許你還想看

美團OCTO萬億級數據中心計算引擎技術解析

| 美團針對Redis Rehash機制的探索和實踐

Redis高負載下的中斷優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章