raft經過集羣的方式爲客戶提供強一致、高可用的服務。強一致表如今客戶端看的都是最新的數據。高可用性表示不論是是網絡故障仍是節點宕機都不會影響客戶端對最新數據的獲取。主要經過副本讀取LOG的方式進行,根據日誌中記錄的操做來更新狀態。
複製代碼
Raft在正常工做狀態下如上圖所示,在一個raft group中只有一個leader,由leader負責客戶端對raft數據的讀寫,當客戶端有數據寫入需求的時候交給leader,而後leader經過LOG的方式將數據變化發送給其它節點(follower),只有在超過半數以上的節點確認寫入的狀況下才能commit而且返回給客戶端成功的信息。follower和leader之間經過心跳獲取各自的狀態。網絡
在leader由於網絡或者主機宕機等緣由發生故障,follower在必定時間內未收到來之leader的心跳信息,follower就會認爲leader發生了故障進而啓動選舉程序進入candidate狀態,開啓新一輪任期(term=當前term+1)。首先會給本身投票一票,而後向其它節點發送拉票信息,其它的節點判斷是否贊成。有以下狀況會致使其餘節點投拒絕票:spa
一、已經投過同意票了,一個節點只能投票一次日誌
二、其它節點的term或log比發起拉票節點的高。code
根據投票的狀況會出現3中結果,本身贏得選舉、其它節點贏得選舉、未產生結果。cdn
本身贏得選舉,當一個candidate節點得到超過半數的同意票時候這個節點就贏得選舉成爲leader,節點的投票是根據先到先得原則進行投票的,誰先向我拉票就把票給誰。blog
他人贏得選舉,沒贏得過半票數,或者在選舉的過程當中受到了leader的信息(term比本身大)那麼本身就變成follower。同步
未產生結果,若是兩個節點同時發起投票,首先本身給本身投一票,而後就沒有票給其它人了,這樣產生的結果就是沒人得到半數選票,在這種狀況下raft會要求各個節點在一個隨機時間以後再次發起投票(term+1),由於兩個節點發起再次投票的時間不一樣,因此就不會出現沒票的狀況。it
每條日誌保存了對於的數據變動,以及日誌編號和term號碼。leader在發生log給follower的時候還會發送上一條日誌的信息(序號和任期),若是follower發現接收到的log中記錄的上一條log的信息和本身當前的不一致,說明中間存在數據差別,這個時候follower就會要求leader發生缺失的log。io
備註:不是全部的日誌都已經提交 從圖中能夠看出,在完成了選舉以後有的follower比leader的數據多,有的比leader的數據少。用f爲列,看看什麼狀況下會發生這種狀況:入門
在任期2的時候f爲leader,這個時候寫入了3條數據,可是沒有提交就被下線了,在任期3的時候又上線,而後由寫入了5條數據,以後由其餘節點成爲leader。新的leader會檢查出這個數據的不一致,而後對這個不一致就行修復,具體的作法的依次向前比對數據,直到找到重合的數據爲止,在圖中是log=3的位置,而後從新發送log=3~10的全部數據。總結起來就是leader會要求全部的follower和本身的數據保持一致。
還有一種狀況,可能會致使即便多個超過半數的節點已經提交了日誌,依然有可能被其餘新選的Leader覆蓋日誌
一、在a狀態下,S1爲leader,當前的term=2,只是完成了部分日誌寫入(沒有同步到s3/s4/s5),這個時候S1被下線了。
二、在b中S5被選S四、S3選舉爲新的leader(由於S5得到了S三、S4的選票就能夠成爲leader),而且S5在log=2的位置接收到了新的請求(term=3)
三、在c的狀況下,S1上線同時有被選舉爲leader,而且在log=3的時候作了數據的寫入(term=4),同時由於leader作數據校驗的時候,同步了log=2(term=2)給s3,這個時候log=2的數據已經知足提交的條件了(超過半數),可是這種狀況下是不能提交的。
四、假設在上述狀況下發生了提交,那麼若是S1再次下線,那麼S5確定會被選擇爲leader(由於term最大),S5做爲leader以後就會覆蓋以前作的提交(log=2的數據)也就形成了數據異常。
五、怎麼避免?能夠限制leader只能提交當前term的數據,在上述的狀況下,不提交log=2的數據(log=2的數據是term=2的時候寫入的)提交log=4(term=4)的數據,就能夠解決,由於這種狀況下就算S1下線,S5也不會被選舉爲新的leader由於其它的節點的term比S5的term大~
1620秒入門Raft - 知乎