上圖中, 最上面表示的index, S1~S5分別表示的是服務器延刘, (a)~(b) 代表了不同的場景搬素, 每個小塊中的數字表示了itemid祈匙。
現(xiàn)分析如下:
(a) 場景: S1是leader,termId是2鲜侥,寫了一條日志到S1和S2褂始,當前機群表示的leader表示為(termId:2,logIndex:2)描函。
(b) 場景:S1 掛崎苗, S5被選為leader(獲得S3和S4的投票), 并在處于(termid:3, index:2)的位置上接受到了新的entry
(c) 場景:S5 掛狐粱,S1被選為leader, 并且termid:4, s1將index為2,term為2的entry復制到了s3上,此時已經滿足過半數了胆数, 那么此時S1能不能提交index:2上的entry呢肌蜻??
這里有兩種情況:
1 ) 假如s1提交的話必尼,則(index:2蒋搜,term:2)的entry就被應用到狀態(tài)機中了,是不可改變了判莉,此時s1如果掛了豆挽,來到term5,s5是可以被選為leader的骂租,因為按照之前的log比對策略來說祷杈,s5的最后一個log的term是3比s2 s3 s4的最后一個log的term都大。一旦s5被選舉為leader渗饮,即d場景但汞,s5會復制(index:2,term:3)的entry到上述機器上,這時候就會造成之前s1已經提交的index為2的位置被重新覆蓋互站,因此違背了一致性私蕾。
- 假如s1不提交,而是等到term4中有過半的entry了胡桃,然后再將之前的term的entry一起提交(這就是所謂的間接提交踩叭,即使?jié)M足過半,但是必須要等到當前term中有過半的entry才能跟著一起提交)翠胰,即處于e場景容贝,s1此時掛的話,s5就不能被選為leader了之景,因為s2 s3的最后一個log的term為4比s5的3大斤富,所以s5獲取不到投票,進而s5就不可能去覆蓋上述的提交锻狗。
日志覆蓋的2種情況:
commitIndex之后的log覆蓋:是允許的满力,如leader發(fā)送AppendEntries RPC請求給follower,follower都會進行覆蓋糾正轻纪,以保持和leader一致油额。
commitIndex及其之前的log覆蓋:是禁止的,因為這些已經被應用到狀態(tài)機中了刻帚,一旦再覆蓋就出現(xiàn)了不一致性潦嘶。而上述案例中的覆蓋就是指這種情況的覆蓋。
從這個案例中我們得到的一個新約束就是:
Note :
當前term的leader不能“直接”提交之前term的entries
必須要等到當前term有entry過半了我擂,才順便一起將之前term的entries進行提交
所以raft靠著這2個約束來進一步保證一致性問題衬以。
再來仔細分析這個案例缓艳,其問題就是出在:上述leader選舉上,s1如果在c場景下將index為2看峻、term為2的entry提交了阶淘,此時s5也就不包含所有的commitLog了,但是s5按照log最新的比較方法還是能當選leader互妓,那就是說log最新的比較方法并不能保證3.1中的選舉約束即
被選舉出來的leader必須要包含所有已經比提交的entries
所以可以理解為:正是由于上述選舉約束實現(xiàn)上的缺陷才導致又加了這么一個不能直接提交之前term的entries的約束溪窒。
也就是 leader 剛通過選舉成為 leader 的時候,這時候的 commit index 并不能夠保證是當前整個系統(tǒng)最新的 commit index冯勉,所以 Raft 要求當 leader 選舉成功之后澈蚌,首先提交一個 no-op 的 entry,保證 leader 的 commit index 成為最新的灼狰。