探索c#之虛擬桶分片

發表於2015-09-07

背景

關於資料分片討論最多的是一致性hash,然而它並不是分散式設計中的銀彈百試百靈。 在資料穩定性要求比較高的場景下它的缺點是不能容忍的。

比如在Redis分散式快取設計中,使用一致性Hash進行key分片儲存,通過虛擬節點最大化降低新增或刪除節點帶來的影響。這裡強調降低二字,即是它還是有影響的,在一般情況下我們還可以接受。

但是某些場景下要求動態擴容無影響就無法滿足了。

上次(探索c#之一致性Hash詳解)提到過Hash取模的分片演算法,是把資料mod後直接對映到真實節點上面,這造成節點個數和資料的緊密關聯、後期缺乏靈活擴充套件。

而一致性Hash分片演算法多增加一層虛擬對映層,資料與虛擬節點對映、虛擬節點與真實節點再對映。

 

虛擬桶(virtual buckets)

虛擬桶是取模和一致性hash二者的折中辦法。

  • 採用固定節點數量,來避免取模的不靈活性。
  • 採用可配置對映節點,來避免一致性hash的部分影響。

其執行機制如下:

key對虛擬桶層

虛擬桶層採用預設固定數量,比如樓主在專案中預設N=1024。意味之後這個分散式叢集最大擴容到1024個節點,帶來的好處就是mod後的值是不變的(非常重要),這保證了第一層對映挖寶去不受實際節點變化的影響。 關於最大數量,可根據實現需要預先定義好即可,比如Redis官方的糟最大65000個節點,豌豆莢的codis預設也是1024個節點。 當然如果資料量超過1024節點儲存時,可以再起另外個叢集應對。

虛擬桶對實際節點

舉個例子,專案剛開始使用時配置節點對映:
Redis Server1對應桶的編號為0到500。
Redis Server2對應桶的編號為500到1024。

快取資料量增長後需要增加新節點,在加之前需要重新分配節點對應虛擬桶的編號。 比如增加server3並配置對應桶的編號400到600,這時對於key對映虛擬桶層完全無影響。 實際上mod 400到600的真實資料還在另外兩臺節點上,請求過來後還會發生無法命中的影響。
這就要求在增加新節點前,需要在後臺把另外二臺的400到600編號資料拷貝到新節點上面,完成後再新增配置到對映上面。 因為新來請求會命中到新節點,所以另外2臺的400到600編號資料就無用了,需要進行刪除。這種做法就能最大限度(100%)的保證動態擴容後,對快取系統無影響。

 

實現

演算法實現這塊比較簡單,資料遷移、配置等這塊需要單獨的系統來做。

 

 

總結

採取虛擬桶這種預分片的演算法,可以避免一致性hash擴容時引起的快取不命中。文中使用1024個例項作為最大節點數量,實際中是完全足夠用的。如果以後可能超過這個數量,可以部署另外一套1024節點的叢集,最後形成一個超大規模的redis叢集。

關於Redis的整套解決方案可以參考使用豌豆莢的codis。

分享了專案中一些使用經驗,希望對大家有所幫助。

相關文章