Raft 算法學習 續

log的傳播
    當leader收到客戶的寫請求後, 它記錄一個更新log, 然後把log並行的複製給其它server。在多數派完成log複製後, leader向客戶回覆操作成功,以確認操作被提交。如果有follower宕機或處理的速度很慢, leader會一直重試直到成功。我們先看log的組織形式。以term 和 index來標示log 如下圖:
                 1                  2                3                4                5                6                7                8                       log index
  leader    1,x=3         1,y=1          1,y=9         2,x=2          3,x=0         3,x=7         3,x=5          3,x=4                term number, operation
 follower  1,x=3         1,y=1          1,y=9         2,x=2          3,x=0        
 follower  1,x=3         1,y=1          1,y=9         2,x=2          3,x=0         3,x=7         3,x=5          3,x=4  
 follower  1,x=3         1,y=1        
  follower  1,x=3         1,y=1          1,y=9         2,x=2          3,x=0         3,x=7         3,x=5   
              |------------------------------------------提交掉的log-----------------------------------------|

    上面的示意圖慘點, 不過意思到了。
    一條log什麼時候被確認是提交的, 這個由leader來決定。 已經提交的log不會丟失。 ledaer把一條log複製到了多數派就可以認爲這條log被提交了, 同時在leader的log中, 這條log之前的log(即便是前任leader創建的)也就被提交了。 注意, 這裏的當前log應該是由當前leader創建的。 如果是前任留下來的log, 即便複製到了多數派也不能認爲提交。 這個後面專門討論。leader一直追蹤着提交了的最高的log index, 並且在後續的log複製消息中帶着這個信息, 這樣follower就知道哪條log被認爲提交了, 從而應用相應的操作到自己到狀態機中。leader在一個給定的term中給定的index, 只會至多創建一條log。 這個log在log序列中的位置永遠不會改變。leader在複製log給follower的時候, 總是會攜帶當前log的前一條log的term和index信息。 如果一個follower在自己本地信息中無法找到對應的log信息, 則拒絕這個複製log的請求。有了這個條件, 如同數學歸納法一樣, leader知道只要log複製成功了, 那麼follower的log序列就和自己的log序列是完全一致的。
    在正常情況下, leader和followers的log序列是一致的, 上面這種檢查不會失敗。 但是如果有leader宕機, 或者leader和follower交錯宕機等複雜情況, 就會發生這種序列的不一致, 比如:
        1        2        3        4        5        6        7        8        9        10        11        12              log index
       
L       1        1        1        4        4        5        5        6         6        6                                     term number
a       1        1        1        4        4        5        5        6         6                   
b       1        1        1        4        
c       1        1        1        4        4        5        5        6         6        6        6                            
d       1        1        1        4        4        5        5        6         6        6        7          7
e       1        1        1        4        4        4        4
f        1        1        1        2        2       2        3        3          3        3        3

    上圖中 L行是 term8 的leader, a -f 是可能的follower。 當L現在成爲leader的時候, follower 有可能缺失log(a-b), 有可能存在多出來的沒提交的log(c-d)也有可能兩者都有(e-f)。比如f的出現, 可能是因爲在term2的時候它是leader, 然後接受三個寫請求, 寫了三個log。在都沒有複製到其它follower的時候自己宕機, 然後迅速重啓, 又成爲了leader(這時term變爲3), 又接受了5個寫請求。 寫了5條term3的log, 然後宕機。
    在Raft中, 如果leader發現了這種不一致, 它會要求把自己的log複製給follower從而讓follower跟自己達到一致。 這就是說, follower的log可能被覆寫(leader的從來不會被覆寫)。因爲leader在選舉的時候是有限制條件的(包含所有的已經提交的log), 所以這樣的同步是安全的。leader要找到follower跟自己一致的log, 然後刪除follower後面的log把自己的同步給follower。 leader是通過這種方式來做的: 首先, leader爲每個follower保存一個next index指針。用這個指針來標記leader應該發給follower的下一條log。 當一個server成爲leader的時候, 它初始化所有follower的這個指針爲自己最後一條log的下一條, 然後跟follower覈對(在複製log的消息中),如果不符合則前移指針, 直到找到符合的爲止。在找到並且同步好log之後, follower的log序列就應該跟leader完全一致了, 並且一直保持下去。
 
提交前任的log:
    前面提到, 一個leader一旦把本term裏的一個log複製給了多數派就可以認爲這個log被提交了。當一個leader在完成多數派複製之前就宕掉, 下任leader會嘗試完成上一任的複製, 這時候複製到多數派後, leader不能確認這個log是提交的。 只有自己本term內又一個新的log複製到多數派後才能確認本term的log和之前的所有log(包括上任那個)是提交的。看下面的演示:

                    1       2               1       2                 1     2      3                1     2     3              1    2    3
                  ------------------------------------------
          s1      1       2    |        1       2       |       1     2      4    |         1     3          |        1    2    4
          s2      1       2    |        1       2       |       1     2            |          1     3         |        1    2    4
          s3      1             |        1                |       1     2            |          1     3         |        1    2    4
          s4      1             |        1                |       1                   |          1     3         |        1
          s5      1             |        1        3       |       1     3            |          1     3        |         1    3
                        a        |             b            |              c             |             d           |                e
        解釋一下上面的圖。 s1是leader的時候, 將term2複製到s2就宕機了(a列的狀況)。  然後S5成爲candidate進入term3, 並且收到了S3,S4和它自己的投票,從而成爲term3的leader。它在index爲2的位置寫了一個不同的內容, 還沒複製出去就宕機(列b)。s1重啓, 並且被選爲leader。在成爲leader的過程中, 經過多數派投票, 所以S1知道term2 term3都是過時的了, 所以它的term是4, 這個時候S1繼續前面2的複製, 把2的log複製給了S3從而達到了多數派(列c),但是這個時候是不能認爲term2的log是提交了的, 因爲如果這個時候S1宕機, S5重啓併成爲leader(因爲S5當前term是3, 在S1宕機後, 它的term最大也就是log最新, 可以被選爲leader), S5會把自己的index 2位置term3的log複製給S2-S4, 從而覆蓋掉了term2的log(列d)。但是, 
如果S1(列c狀態)完成了本term, 也就是term4的一條log到多數派到複製, 則可以認爲term2, term4都被提交了。 因爲這時s1再宕機, s5是無法被選成leader的(列e)因爲 s5不滿足必須包含所有提交log的約束(見leader選舉時, leader的log不能比任何其它server的舊的要求)。
   
    log傳播完了, 最核心的部分也就都介紹完了。 其餘比如集羣成員變化, log壓縮等都不在這裏細說。感興趣都同學自行閱讀原文。







<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
閱讀(8) | 評論(0) | 轉發(0) |
給主人留下些什麼吧!~~
評論熱議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章