Geo-replication: 從 Copysets 到 Tiered Replication

對於分佈式存儲系統,我們都會使用多副本的機制來保證數據的安全性。譬如對於 TiKV 來說,我們默認會使用 3 個副本,如果需要更高等級的安全性,譬如在銀行領域,我們則會使用 5 個副本。但無論使用幾個副本,我們都會面臨一個問題,我們如何在集羣中放置這些副本。

機器都是有壽命的,磁盤,內存等硬件在運行的時候也時不時會壞掉。假設現在我們使用 3 個副本,有 N 臺機器,如果同時有 3 臺機器壞掉,而悲催的是剛好 3 個副本在這 3 臺機器上面,那麼我們就會面臨數據丟失問題。所以我們需要儘量減少數據丟失的概率。

Random replication

最簡單的做法就是選擇任意 3 臺機器來放置副本,但是這個策略其實不好。假設機器壞掉的概率是 1%,對於 3 副本來說,同時壞掉的概率是 0.0001%,看起來這個是很低的,但實際中,我們不光只有一份數據。

在 TiKV 裏面我們會將數據切分成多個 region,每個 region 對應一份數據,在實際生產環境中,region 數量是非常多的,一些集羣都已經過了百萬了,這時候如果有 3 個節點同時損壞,一些 region 副本全丟掉的概率會非常的大。

下圖是 Copysets paper 裏面給出的數據,可以看到,那麼隨着節點數的增多,使用隨機複製方式的 3 副本掉數據的概率會急劇的增大:

Copysets replication

爲了解決 Random replication 的問題,有人提出了 Copysets,也就是論文 Copysets: Reducing the Frequency of Data Loss in Cloud Storage,相比於使用 random 方式,Copysets 引入了 scatter width,將整個集羣節點進行分組,然後在分組的集合裏面選擇節點進行復制。

Copysets 的算法其實比較簡單,假設集羣數量是 N,複製因子是 R(其實就是選擇幾個副本),scatter width 是 S,那麼:

  1. 創建 S / (R - 1) 個節點排列
  2. 將每個排隊分成 R 組
  3. 隨機選擇一個節點當成副本的 primary 副本
  4. 在分組的包含 primary 節點的集合裏面隨機選擇 secondary 副本

譬如,假設我們有 9 個節點,R 是 3,而 S 是 2,那麼就有 2 / (3 - 1) = 1 個排列,譬如 [1, 6, 5, 3, 4, 8, 9, 7, 2],然後我們分成 3 組,也就是 [1, 6, 5], [3, 4, 8], [9, 7, 2]

對於 3 副本,假設我們選擇 1 作爲 primary 副本存放的節點,那麼剩下兩個 secondary 副本只能在 6 和 5 上面選取。

使用 Copysets,能有效的降低丟失數據的概率,根據 Paper 裏面描述,在 5000 個節點下面,如果有 1% 的節點同時掛掉,random 丟失的概率是 99.99%,而 Copysets 則是 0.15%。

Tiered Replication

當然,copysets 並不是銀彈,它並不能解決集羣動態擴容的問題,於是 copysets 的作者,繼續研究了另一個解決方案,也就是 Tiered replication,Paper 是 Tiered Replication: A Cost-effective Alternative to Full Cluster Geo-replication

Tiered Replication 的原理其實也比較簡單,仍然有 Copysets 的概念 scatter width S,會將整個集羣分成多個 Copysets,每個 Copysets 的大小是 R,對於每個節點,必須保證它至少在 S 個 Copysets 裏面。另外,Tiered Replication 裏面也有 primary 和 backup 節點的區分,通常兩個副本會放在 primary 節點裏面,而第三個副本則會放到 backup 節點裏面。

Tiered Replication 的算法比較簡單,大概來說:

  1. 所有節點開始的 scatter width 是 0,也就是沒有屬於任何 Copysets。
  2. 創建一個 Copysets,選擇最小 scatter width 的 R 個節點加進去。
  3. 重複上面的過程,直到所有的節點的 scatter width 至少是 S。

詳細的算法可以看 Paper,而源碼在這裏,使用起來還是很簡單的,譬如:

# not rack aware
>>> trepl.build_copysets(['node1', 'node2', 'node3'], R=2, S=1)
[['node1', 'node2'], ['node1', 'node3']]

# rack aware, node1 and node2 can not share a copyset since they're in
# the same rack
>>> rack_map = { 'node1': 'rack1', 'node2': 'rack1', 'node3': 'rack3' }
>>> trepl.build_copysets(
      rack_map.keys(), R=2, S=1,
      checker=trepl.checkers.rack(rack_map),
    )
[['node1', 'node3'], ['node2', 'node3']]

對於集羣的動態更新,譬如新加入一個節點,就直接按照上面的算法,將這個節點加入到不同的 Copysets 裏面,直到這個新加入的節點的 scatter width 爲 S。而對於刪除節點,一個簡單的做法就是將包含這個刪除節點的 Copysets 幹掉,而在這些 Copysets 裏面的其他正常節點的 scatter with 也會減少,然後會創建新的 Copysets 替換老的。在老的 Copysets 裏面的正常副本可能會重新複製到其他節點上面。

總結

說了這麼多,對 TiKV 來說有什麼借鑑意義呢?現在 TiKV 是通過打 label 的方式來支持 Geo-replication 的,假設我有 3 個 Rack,每個 IDC 有 3 臺機器,我們會給每個啓動在機器上面的 TiKV 進程打上類似 rack = rack1, host = host11 這樣的標籤,PD 就會將 3 個副本分散到不同 Rack 的不同機器上面,但在 Rack 機器的選擇上面,我們還是一個 random 算法。也就是說,即使能保證副本在不同的 Rack 上面,但隨着每個 Rack 機器數量的增多,我們 3 副本同時丟失的概率就會增大,所以自然需要一個更好的副本複製策略。如果你對這方面感興趣,歡迎聯繫我 [email protected]

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