Geo-replication: 從 Copysets 到 Tiered Replication

weixin_34232744發表於2018-11-18

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

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

Random replication

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

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

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

2224-3736d6ed22a7159f.png

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 副本同時丟失的概率就會增大,所以自然需要一個更好的副本複製策略。如果你對這方面感興趣,歡迎聯絡我 tl@pingcap.com

相關文章