淺談分散式儲存系統的資料分佈演算法

weixin_34377065發表於2018-07-01

前言

分散式儲存系統 面臨著的首要問題,就是如何將 大量的資料 分佈在 不同的儲存節點 上。無論上層介面是 KV 儲存物件儲存塊儲存、亦或是 列儲存,在這個問題上大體是一致的。本文將介紹如何 分散式儲存系統做資料分佈目標 及可選的 方案,並試著總結和權衡他們之間的關係及優缺點。

淺談分散式儲存系統的資料分佈演算法

正文

(一). 指標

這裡假設 目標資料 是以 key 標識的 資料塊物件。在一個包含 多個儲存節點 的叢集中,資料分佈演算法 需要為每一個給定的 key 指定 一個多個 對應的 儲存節點 負責,資料分佈演算法 有兩個基本目標:

  • 均勻性(Uniformity):不同儲存節點的 負載 應該 均衡

  • 穩定性(Consistency):每次一個 key 通過 資料分佈演算法 得到的 分佈結果 應該保持 基本穩定,即使再有儲存節點發生變化的情況下。

可以看出,這兩個目標在一定程度上是 相互矛盾 的。當有 儲存節點增加或刪除 時,為了保持穩定應該 儘量少 的進行 資料的移動重新分配,而這樣又勢必會帶來 負載不均衡。同樣追求 極致均勻 也會導致較多的 資料遷移

所以我們希望在這兩個極端之間,找到一個點以獲得合適的均勻性和穩定性。除了上述兩個基本目標外,工程中還需要從以下幾個方面考慮資料分佈演算法的優劣:

  1. 效能可擴充套件性:這個主要考慮的是演算法相對於 儲存節點規模時間複雜度。為了整個系統的可擴充套件性,資料分佈演算法不應該在叢集規模擴大後顯著的增加執行時間。

  2. 考慮節點異構:實際工程中,不同 儲存節點 之間可能會有很大的 效能容量差異,好的資料分佈演算法應該能很好的應對這種 異構,提供 加權的資料均勻

  3. 隔離故障域:為了 資料的高可用,資料分佈演算法應該為每個 key 找到 一組儲存節點,這些節點可能提供的是 資料的映象副本,也可能是類似 擦除碼 的副本方式。資料分佈演算法應該儘量 隔離 這些副本的故障域,如 不同機房不同機架不同交換機不同機器

(二). 演進

看完演算法的評價指標後,接下來介紹一些可能的方案演進,並分析他們的優劣。這裡假設 key 的值足夠分散。

1. Hash

一個簡單直觀的想法是直接用 Hash 來計算,簡單的以 Key雜湊對節點數取模。可以看出,在 key 足夠分散的情況下,均勻性 可以獲得,但一旦有 節點加入退出 時,所有的原有節點都會受到影響。穩定性 無從談起。

2. 一致性Hash

淺談分散式儲存系統的資料分佈演算法

一致性 Hash 可以很好的解決 穩定性問題,可以將所有的 儲存節點 排列在收尾相接的 Hash 環上,每個 key 在計算 Hash 後會 順時針 找到先遇到的 儲存節點 存放。而當有節點 加入退出 時,僅影響該節點在 Hash 環上 順時針相鄰後續節點。但這有帶來 均勻性 的問題,即使可以將儲存節點等距排列,也會在 儲存節點個數 變化時帶來 資料的不均勻。而這種可能 成倍數的不均勻 在實際工程中是不可接受的。

3. 帶負載上限的一致性Hash

一致性 Hash節點變化時不均勻的問題。Google2017 年提出了 Consistent Hashing with Bounded Loads 來控制這種 不均勻的程度。簡單的說,該演算法給 Hash 環上的每個節點一個 負載上限1 + e 倍的 平均負載,這個 e可以自定義。當 keyHash 環上 順時針 找到合適的節點後,會判斷這個節點的 負載 是否已經 到達上限,如果 已達上限,則需要繼續找 之後的節點 進行分配。

淺談分散式儲存系統的資料分佈演算法

如上圖所示,假設每個桶 當前上限2,紅色的小球按序號訪問,當編號為 6 的紅色小球到達時,發現順時針首先遇到的 B(3,4)C(1,5)都已經 達到上限,因此最終放置在桶 A 裡。

這個演算法最吸引人的地方在於 當有節點變化 時,需要遷移的資料量是 1/e^2 相關,而與 節點數資料數量 均無關。

也就是說當 叢集規模擴大 時,資料遷移量 並不會隨著顯著增加。另外,使用者可以通過調整 e 的值來控制 均勻性穩定性 之間的權衡,就是一種 以時間換空間 的演算法。總體來說,無論是 一致性 Hash 還是 帶負載限制一致性 Hash,都無法解決 節點異構 的問題。

4. 帶虛擬節點的一致性Hash

為了解決 負載不均勻異構 的問題,可以在 一致性 Hash 的基礎上引入 虛擬節點。即 hash 環上的 每個節點 並不是 實際儲存節點,而是一個 虛擬節點。實際的 儲存節點 根據其 不同的權重,對應 一個多個虛擬節點,所有落到相應虛擬節點上的 key 都由該 儲存節點負責

如下圖所示,儲存節點 A 負責 (1,3](4,8](10, 14],儲存節點 B 負責 (14,1](8,10]

淺談分散式儲存系統的資料分佈演算法

這個演算法的問題在於,一個 實際儲存節點加入退出,會影響 多個虛擬節點的重新分配,進而引起 很多節點 參與到 資料遷移 中來。

另外,實踐中將一個 虛擬節點 重新分配給 新的實際節點 時,需要將這部分資料 遍歷 出來 傳送給新節點。我們需要一個更合適的 虛擬節點切分分配方式,那就是 分片

5. 分片

分片雜湊環 切割為 相同大小的分片,然後將這些 分片 交給 不同的節點 負責。

注意這裡跟上面提到的 虛擬節點 有著很 本質的區別分片的劃分和分片的分配被解耦

一個 節點退出 時,其所負責的 分片 並不需要 順時針合併 給之後節點,而是可以更靈活的 將整個分片 作為一個 整體 交給 任意節點。在實踐中,一個 分片 多作為 最小的資料遷移備份單位

淺談分散式儲存系統的資料分佈演算法

而也正是由於上面提到的 解耦,相當於將原先的 key節點對映 拆成了兩層。需要一個 新的機制 來進行 分片儲存節點對映。由於 分片數 相對 key 空間已經很小並且 數量確定,可以更精確地初始設定,並引入 中心目錄服務 來根據 節點存活 修改 分片的對映關係。同時將這個 對映資訊 通知給所有的 儲存節點客戶端

淺談分散式儲存系統的資料分佈演算法

上圖是 分散式KV儲存 Zeppelin中的 分片方式Key Space 通過 Hash分片分片及其副本 又通過一層對映到 最終的儲存節點 Node Server

6. CRUSH演算法

CRUSH 演算法本質上也是一種 基於分片 的資料分佈方式,其試圖在以下幾個方面進行優化:

  • 分片對映資訊量:避免 中心目錄服務儲存節點客戶端之間 互動大量的 分片對映資訊,而改由 儲存節點客戶端 自己根據 少量穩定 的叢集節點拓撲和確定的規則自己計算分片對映。

  • 完善的故障域劃分:支援 層級故障域控制,將 同一分片不同副本 按照配置劃分到 不同層級故障域中

客戶端儲存節點 利用 key儲存節點拓撲結構分配演算法,獨立的進行 分片位置 的計算,得到一組負責對應 分片副本儲存位置

如圖所示是 一次定位 的過程,最終選擇了一個 row 下的 cab21cab23cab24 三個機櫃下的三個儲存節點。

淺談分散式儲存系統的資料分佈演算法

節點變化 時,由於 節點拓撲 的變化,會影響 少量分片 資料進行遷移,如下圖是加入 新節點 引起的 資料遷移。通過良好的 分配演算法,可以得到很好的 負載均衡穩定性CRUSH 提供了 UniformListTreeStraw 四種分配演算法。

(三). 應用案例

常見的 分散式儲存系統 大多采用類似於 分片資料分佈和定位方式

  1. Cassandra/Dynamo:採用 分片 的方式並通過 Gossip 協議在對等節點間通訊;

  2. Redis Cluster:將 key Space 劃分為 slots,同樣利用 Gossip 協議通訊;

  3. Zeppelin:將資料分片為 Partition,通過 Meta 叢集提供 中心目錄服務

  4. Bigtable:將資料切割為 Tablet,類似於可變的分片,Tablet Server 可以進行分片的切割,最終分片資訊記錄在 Chubby 中;

  5. Ceph:採用 CRUSH 方式,由 中心叢集 Monitor 提供並維護 叢集拓撲 的變化。


歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章