CockroachDB和TiDB中的Multi Raft Group是如何實現的?

CockroachDB 和 TiDB 中都提到使用了 Multi Raft Group 來解決單 leader 的性能瓶頸。目前看下來資料很少,想問一下集群的管理這塊具體是如何做的?

CockroachDB 應該是把 key 的空間拆分成多個 range,每個 range 由一個 Raft group 來管理。這個地方目前能想到兩個辦法來處理

1. 多個 raft group 相互獨立,僅僅是公用一個網路連接而已,其他的各自負責各自的選舉和日誌 commit。這樣的話極端情況下會存在所有 group 的 Leader 都在一台機器上的問題,還是會有性能瓶頸。而且 range 的拆分和合併應該也不太好處理

2. 存在一個主的 Raft group,用來管理 range 的拆分合併,決定某個 Raft group 的 Leader 在哪一台機器上。其餘的 Raft group 僅僅處理除了 Leader 選舉以外的部分(日誌 commit)。這種方式處理起來會更簡單高效 ,但是對 Raft 協議本身的改動比較大,實現起來應該也會相對複雜

或者 TiDB 和 CockroachDB 使用的其他的辦法?希望能夠得到解答。


TiDB 的多個 Raft Group 相互獨立,各自負責各自的選舉和日誌 commit。TiDB 中會部署一個叫 PD 的組件pingcap/pd,所有的 Raft Group 都要向 PD 彙報自己的信息,PD 會根據這些信息,對 leader 的位置、副本的位置等狀態進行調度,盡量保證 leader 在機器之間的均勻分布。這裡有一篇文章可以看看 知乎專欄。後續還會有更多關於 PD 的文章。


嘗試回答一下CockroachDB在multi raft方面做了什麼事情

multiraft的問題 樓上 @人類的好朋友 已經說了,就是大量流量耗費在心跳上,故做了個心跳合併的優化。這裡有個設計文檔,cockroachdb/cockroach,原理是引入了一種Node級別的lease,只要Node級別的lease有效,那麼這個Node上的所有的raft group的leader的lease都是有效的。這樣就不必頻繁更新range級別的lease,只需要更新Node級別的lease即可

還有一個優化就是關閉某一些不活躍的raft group,基於的假設就是資料庫這麼大,其實,很多數據很長時間根本都碰不到,所以維護著lease沒啥用。設計文檔: cockroachdb/cockroach


cockroachDB的文檔還是比較多的。關於設計的有:

cockroachdb/cockroach ,早幾個月的時候的翻譯了當時的設計文檔:

cockroachdb設計翻譯 | 李黃河BLOG

還有官方的:Blog | Cockroach Labs

關於key空間,cockroach是把保存一個全局的key空間,用第一個range來保存range的元數據(那個key在哪個range上),默認一個range是64M,可支持16T的存儲,如果要更大的存儲空間,cockroach是通過兩級索引來定址,最大支持4EB的空間。每個rang有多個副本,組成一個raft group。

你的第一個問題:所有leader都集中在一個server上。cockroach有一個rebalance機制來拆分或者合併range。這個rebalance的主要依據就是range的大小以及讀寫等待時間,保證一個server不會過載。

第二個問題:並不存在一個主range group,所有的range group都是對等的。range的拆分合併完全由range leader根據統計信息獨立進行。


多個raft group邏輯上獨立,物理上會共用一些東西,比如網路鏈接,比如raft日誌等。

既然raft group的邏輯上是獨立的,那他們的raft leader也是相互獨立的。

實際上,cockroach在raft之上加了租期協議,真正的lease holder才承擔了讀寫壓力,lease granter只承擔了寫壓力。

租期協議裡面的lease holder是可以被控制的,只需要控制lease holder不要在同一個節點,就可以避免多個range的lease holder在同一台機器的問題。

range本身也支持分裂合併。實現也比較複雜。

也就是說,range本身是支持lease holder轉移,也支持分裂合併。至於外面如何控制這些動作,還沒有看的太清楚,以後看完了代碼再來回答吧。


援引自 cockroach 博客 的解釋

cockroach 的底層 scaling 存儲本身可以認為是一張無限大的有序 KV map,上層封裝了一層 SQL。他 sharding 的方式是通過 range 實現的。對一組 64M 大小數據的範圍內的 key 做冗餘,用二級 metadata range 可以理論上存儲 4EB 的數據。

舉個例子,五節點打散三副本的一個 range 做冗餘,是成本性能和效率上比較典型的一個折衷。像你說的leader集中的情況是比較少的,因為三副本是打散分布到不同節點上的,所以三副本的交集不會太集中,單點的壓力還是很少的。

另外租約的存在(不知道算不算在 multi raft 演算法內),也可以緩解集中化的壓力,通過獲得授權的租約旁路一些「可以本地化」的請求(比如只對一個 replica 的操作以及一些能保證數據不變的一段時間的讀請求),來緩解主的壓力,這個最早我記得在 GFS 裡面看到過是這麼設計的。

另外 gossip 的協議有點像交換機的生成樹協議,是通過互相傳播自己的負載和位置信心來傳播信息的,沒有中心化的決策節點,這樣的好處就是無中心化,不會依靠一個中心的節點來做負載均衡,而且整個系統就需要一個二進位文件不依賴任何的其他服務。

下面是網路優化的部分,如你所說是多個 raft group 多路復用了網路請求。

cockroach 對每個冗餘也就是 range 的副本是通過 raft 實現的,所以如果數據量一大就會造成,每個節點上多個 range 之間的網路通信過於頻繁。

如圖是一個 range 在三節點上的三副本的一個 raft group 之間有網路通信。

但是如果 range 變多的話,就會很複雜,如下圖,是四個節點之間大概8個 (如果我沒看錯顏色的話) range 的 raft group 之間通信。

很明顯網路 RoundTrip 太多了。針對這個的優化就是 MultiRaft 了,說白了就是把網路請求 batch up,變成下面的形式。

這樣網路壓力就會小很多。針對這個的優化和應用本身的實現是耦合的,作者也嘗試把這個優化加到 etcd/raft 當中,但是最後的決定是增加 RawNode 這樣的無線程安全的介面給應用層實用,方便對心跳等請求的合併,所以你會看到有個非線程安全的RawNode的實現。

具體到 cockroach 的實現是可以找到相應的代碼的,省略無關代碼就如下。

在發送消息的時候檢查是否有可以整合的請求。

func (r *Replica) sendRaftMessage(ctx context.Context, msg raftpb.Message) {
for range {
// 迭代每個 follower 發送消息
// 對消息進行緩存
if r.maybeCoalesceHeartbeat(ctx, msg, toReplica, fromReplica, true) {
continue
}
}
}

循環取出緩存的消息,注意因為是整合了消息,所以對消息來說有延遲,這裡稍微加快了頻率,彌補這個延遲。

// Since coalesced heartbeats adds latency to heartbeat messages, it is
// beneficial to have it run on a faster cycle than once per tick, so that
// the delay does not impact latency-sensitive features such as quiescence.
func (s *Store) startCoalescedHeartbeatsLoop() {
s.stopper.RunWorker(func() {
ticker := time.NewTicker(s.cfg.CoalescedHeartbeatsInterval)
defer func() {
ticker.Stop()
}()

for {
select {
case &<-ticker.C: s.sendQueuedHeartbeats() case &<-s.stopper.ShouldStop(): return } } }) }

在 Store 這個層面是對每個 Replica (一個 raft group 的成員) 是有感知的,但是每個 raft group 是獨立的,只是在發送是會檢查對方節點是否和現在的 raft group 有交集,
從而嘗試合併消息的發送, 你可以理解為在節點之間的消息通道上對不同 raft group 之間多路復用。
這就是 MultiRaft 對多個 raft group 的網路吞吐做的一個優化,代價是可能造成消息的延遲,因為畢竟是被緩存到隊列里了。

引用自 MultiRaft 解析


關於第一個問題:raft的選舉確實是不可控的,但是在CockroachDB中加入了transferLeader的邏輯,可以參考raft的博士論文。

第二個問題沒明白什麼意思,raft選舉是raft協議的一部分。


推薦閱讀:

raft協議疑問?
分散式一致性演算法是如何解決少數派節點的寫順序一致性問題的?
網路遊戲如何保證數據一致性?
raft協議應用方面的疑問?

TAG:分散式系統 | 分散式一致性 | Paxos | TiDB | CockroachDB |