Quorum 和唱票那回事
作者 | 奇伢
來源 | 奇伢云存儲
關于 Quorum 的兩個維度
前幾回說了那么多框架,設計思想的文章。今天分享一個很小的點,etcd 的 quorum 是怎么實現的?
Quorum 機制本質就是一個關于多數派的事情,這個多數派應用的有兩個方面:
選舉過程:獲得多數節點投票的節點才能獲勝,成為 Leader ;
運行過程:被多數節點 commit 的日志位置,這個才是被集群可靠記錄的位置。被集群 commit 的日志才能被應用 apply ;
那么這里有兩個小思考問題:
既然是選舉過程,那怎么選舉結果唱票的?
既然是運行過程,那集群的這些節點怎么確認集群的 commit 位置?
有選舉自然有唱票
唱票是在選舉流程中的一個步驟。還記得以前選班干部的時候,在黑板上寫“正”字,誰得票多誰就獲勝當選。
etcd 里面也有選舉,也就是 Leader 的選舉。Leader 獲勝的依據是的票滿足大多數,也就是滿足 quorum 機制。
今天我們就來看看 etcd 的唱票是怎么做的?
很簡單的思路,我們給每個參與選舉的朋友計數,得票超過半數的,那么就勝出。
比如說 A,B,C,D,E 五個人競選,那么得到 3 票的就可以勝出。
來看看 etcd 的唱票
選舉屬于 quorum 機制,代碼位于 etcd/raft/quorum/ 下。quorum 的核心實現在 MajorityConfig 的結構體,其實就是個 map 的封裝:
type?MajorityConfig?map[uint64]struct{}這個 map 的 key 是節點的 id,這里面包含了集群的節點,map 的 value 不重要,所用用的是 struct{} 類型。
思考個小問題:那既然 value 不 care ,那為什么不用 slice 結構?
其實就是為了查找的需求,map 的查找是常數級別,value 又用的 struct{} ,不占空間,一舉兩得。
唱票和集群 commit 的實現就是它的方法,我們先看下唱票的實現:
//?etcd/raft/quorum/majority.go func?(c?MajorityConfig)?VoteResult(votes?map[uint64]bool)?VoteResult?{//?搞個長度為?2?的數組ny?:=?[2]int{}//?遍歷集群節點for?id?:=?range?c?{v,?ok?:=?votes[id]if?!ok?{//?暫時沒投票的missing++continue}if?v?{//?投票贊同的ny[1]++}?else?{//?投票拒絕的ny[0]++}}q?:=?len(c)/2?+?1if?ny[1]?>=?q?{//?選舉成功:得票數超過半數,,比如 votes =>?[yes, yes, yes]return?VoteWon}if?ny[1]+missing?>=?q?{//?未知情況:不確定成功,也不確定失敗return?VotePending}//?選舉失敗return?VoteLost }唱票的實現很簡單,就如下幾個步驟:
遍歷集群節點;
統計誰贊同了、誰拒絕了、誰還沒投票;
唱票的結果有三種:成功,失敗,待定;
贊同投票的超過半數( len(c)/2+1 ),則勝利;
這實現可太簡單了,就是一個遍歷投票結果,寫“正”字,“正”字超過半數則勝出。
集群的節點怎么確認集群的 commit 位置?
集群內被多數節點 commit 的位置才是集群的 commit 點。也就是說這個也需要滿足 quorum 。這個就有意思了。
關鍵步驟:排序,然后取中間的位置。
取的這個中間的位置就是滿足 quorum 的 commit 。
//?etcd/raft/quorum/majority.go func?(c?MajorityConfig)?CommittedIndex(l?AckedIndexer)?Index?{//?遍歷集群節點:取出每個節點的 commitfor?id?:=?range?c?{if?idx,?ok?:=?l.AckedIndex(id);?ok?{srt[i]?=?uint64(idx)i--}}//?排個序insertionSort(srt)//?取中間,這個位置就是大多數?commit?的位置,屬集群共識pos?:=?n?-?(n/2?+?1)return?Index(srt[pos]) }這個實現就很有意思了,撈出每個節點當前的 commit 位置,組成一個數組,然后給這個數組排個序,取中間的位置。這個位置就是集群的 commit 位置,也就是 apply 的位置。
先把集群每個節點的 commit 位置取出來,是這樣的:
后來排個序是這樣的,黑色的節點 commit 位置則是集群的 commit 位置:
總結
Quorum 機制是分布式系統中很重要的理論部分,這是一個關于多數派的機制。etcd 關于多數派有兩個方面:Leader 選舉和 raft 日志運行;
etcd 的唱票實現非常簡單,就是一個計數“正”字的實現,用一個 map 記錄集群的節點,投票計數超過多數則勝出;
etcd 確認集群 commit 位置則是先把每個節點的 commit 位置放在數組,然后排個序,然后取中間位置,這個位置就是集群的 commit 位置;
多數節點 commit 過的日志才是集群 commit 的位置,集群 commit 的日志才能 apply ,這個要記住嘍;
集群 commit?位置將由 Leader?通過心跳或者日志復制的消息告訴其他節點;
往期推薦
虛幻引擎5上的《黑客帝國》全新體驗,愛了愛了
元宇宙真的是割韭菜嗎?
Redis會遇到的坑,你踩過幾個?
核彈級漏洞,把log4j扒給你看!
點分享
點收藏
點點贊
點在看
總結
以上是生活随笔為你收集整理的Quorum 和唱票那回事的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何基于OSS和MTS,快速搭建音视频文
- 下一篇: 高密自智,体小量大,希捷Exos Cor