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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 文/李瓊玖 看到題目,肯定會有讀者不屑一顧,心里想著:才一周能有什么深刻獨特的心得體會,所以在開頭我要感謝點開這篇...
    李瓊玖閱讀 478評論 8 9
  • 「序言」 醉宿,我的神智漸漸清醒。燈火燭明,清風攜花兒的芬芳馥郁卷入我的鼻中。我在那兒?這是……穆王府……我拖...
    橘自閱讀 322評論 1 2
  • 我是一個理財小白,標準的月光族。一直被月光困擾,想擺脫這種處境,讓自己的生活多一份選擇。一個偶然的機會知道了長投,...
    蜀國傻妞閱讀 170評論 1 3
  • 2018年 5月19日 星期二 晴 我是日記星球444號星寶寶李慶龍,這是我的第90篇日記。小伙子就是應該擼起袖子...
    706baf44c38f閱讀 229評論 0 3