第11天講註冊中心大部份會追求A+P, C只能盡力滿足.
來看看etcd怎還是能確保它的集群內的節點, 給答案上還是保證正確的.
一個班級有40個人.
我把一個祕密告訴給班裡的21個人.
我隨便找21個人問, 一定會有1個人知道祕密.
(祕密跟八卦很難不傳出去XDDD)
當然, 這種演算法的寫入不會太高, etcd寫入支持大概1000/s上下,
不適合高併發寫入的場景就是. 但只是維護節點狀態, 做配置管理, 分散式鎖措措有餘.
分散式系統中, 節點之間的一致性很難確保.
因為要在集群中的多個節點在狀態上達成一致, 在程序不會crash, 硬體不會損壞, 不會斷電, 網路可靠沒延遲的理想下......(不會有這情況一直持續的XD).
所以現實情況, 在上面情況發生時, 節點之間的一致性就很難確保了.
為此有一些一致性協議, Raft、Paxos這類的算法來保證集群中的大部份節點都是可用的狀況下, 依然還是可以運作且給出一個正確的結果.
Raft演算法是一種用來管理日誌複製的強一致性算法, Raft相較於Paxos更好理解, 便於構建.
etcd透過Raft演算法把Key-Value放進Raft的日誌來進行同步. 因此etcd叢集的K-V日誌就能同步複製了.
Raft中, 集群內的每個節點都維護了一個有限狀態機.
這狀態機有三種狀態
Leader節點在叢集中指會有一個, 負責處理所有客戶端的請求.
當收到客戶端的寫入請求時, Leader會在本機加上一條對應的日誌, 狀態此時是uncommited, 將其封裝成消息發送給其他集群內的Follower.
只要Follower收到後就會回應給Leader. 如果集群中多數以上(Quorum:(n/2+1), 上篇安裝的例子, 3個節點, 只要Leader複製日誌, 並收到至少1個Follower的回應)都收到了對應的日誌消息時, Leader就會把該日誌紀錄改成committed, 這時就會回response給客戶端了.
Leader也處理讀取請求.
也定期地像集群中的Follower節點發送heart beat, 主要用來防止集群中其他Follower節點的選舉計時器被觸發而發起新一輪選舉.
(國王要定期露臉給子民看, 不然子民就暴動啦XD)
Follower節點不會發送任何請求, 主要就是回應Leader或是Candidate的請求.
也不直接處理Client的請求, 而是把請求重導向給Leader去處理.
由Follower轉變而來, 只要Follower一段時間沒收到Leader發送的heart beat時, 該Follower的選舉計時器就會過期, 把自身狀態從Follower轉成Candidate, 發起新一輪選舉.
Raft中有兩個時間在控制Leader選舉發生, 一個是election timeout.
每個Follower節點只要在固定時間內收不到Leader的heart beat之後, 不會直接發起新一輪的選舉election.
而是等待一段時間之後才切換成Candidate狀態並發起新一輪選舉.
預設是1000ms
source code
每個Follower節點的election timeout值不會完全一樣, 預設會落在[electiontimeout, 2*electiontimeout - 1]這範圍內的millisecond來倒數.
這是因為Leader節點發送heart beat到各Follower節點的過程, 可能會因為瞬間的網路延遲或者程式瞬間卡頓導致些許Delay(even 丟失).
當然如果etcd各節點不是在一個內網, 而是全球網路, 那允許最大是50s.
還有另一個時間是Leader身上的Heartbeat timeout, 用來決定Leader節點多久對Followers發送heart beat的時間間隔.
預設是100ms
集群剛啟動時, 所有節點都是處於Follower狀態, 此時集群內沒有Leader節點.
當Follower節點中的election timeout被觸發時(因為收不到heartbeat), 就會認為Leader故障了導致Leader的Term(任期)過期, Follower這時就會轉成Cadidate狀態, 發起一輪新的選舉.
選舉中, 會出現一個或多個Candidate節點嘗試成為Leader, 如果其中一個Candidate贏得選舉, 該節點就會切換成Leader狀態, 並成為該任期的Leader節點, 直到該任期結束.
是一個全局, 嚴格遞增的正整數, 每一輪選舉, Term就會++, 並且在每個節點都紀錄當前的Term值.
該圖是正常選出Leader時, 各自節點的狀態與擁有的timer.
下篇再來細講選舉過程, 先建立名詞概念.