raft 經典場景分析

1. 基本概念

  • Raft 是一種用來管理日誌複製的一致性演算法nn

  • Raft 比 Paxos 更容易學會nn

  • Raft提供一種一致性場景,就是客戶端調用put(x) = y, 一旦寫入成功,則x的值在raft集群存在且能提供服務的情況下,一定會返回get(x) = y(但並不保證在每台raft機器上都是get(x)=y)

  • 一般的應用場景:

  • WAL(write ahead log)大家都知道,其實也沒那麼高端,就是數據寫入前先記一條日誌,類似會計記賬,某賬戶消費20,然後再去修改賬戶餘額,這樣在餘額本丟了的情況下,就可以用賬戶消費本重新算餘額本

  • WAL只能保證數據在單台機器上不丟且一致,場景上來說還是十分單一的,而目前大部分的數據都是主備的背景下,非同步同步的數據會長期存在不一致

  • 主備同步寫入是一個解決非同步同步數據的好辦法,但是這種方法IO等待太高了(考慮一主四,五備的場景)

2. 基礎場景

2.1 角色

角色講解,Raft一共分為三種角色,leader,follower,candidate,字面意思十分明了;nn

  • leader為集群主節點,整個集群僅有一個leader節點可以存在nn

  • follower為跟隨節點,follower知曉自己的leader,並與leader通信

  • candidate為follower無法聯繫上leader節點後轉化而成,candidate的作用就是在自己無法聯繫上leader的情況下聯繫leader

  • 幾個角色的轉換關係如下圖,值得注意的幾個點:

  • 集群啟動時,沒有leader,而是全部初始化為 follower

  • leader 只能退化為follower,原因顯而易見,leader只會在發現有其他更高term(任期)的leader後退居二線(一般發生在腦裂合併的場景)

  • 理解的時候可以把角色代入級別,follower,candidate,leader的升級序列,角色不會跨級別提升(和現實公司中 不能跨級別晉陞很像,而且沒有例外)

圖片

2.2 節點狀態說明

根據協議,節點並不是無狀態的,節點自身的狀態是持久化且保存的(也就是重啟後不會丟失),節點需要注意的狀態中,比較重要的有:

圖片

  • 和選舉有關的狀態:server 5 處於 Leader的角色,且該leader的 termId = 6nn

  • 和日誌複製有關的狀態:已遞交的日誌index為4,下圖為已遞交的日誌圖示,其中S5的4為實現,代表已遞交,虛線的為未遞交

圖片

2.3 經典場景圖示

2.3.1 初始化選舉場景

圖片

圖1:初始化,所有follower都在等待成為candidate的場景

圖片

圖2:兩個follower先後成為candidate,並發出拉票的場景,注意term已經自動為2,表名candidate對任期,也就是term為自動+1,可以看出由於距離優勢,s2的希望肯定更大

圖片

圖3:由票選獲得3張選票的場景(其中s5的唯一一張選票來自於自身)

初始化時,所有的node都處於follower,且在一段時間內都不成為candidate。為了防止有兩個node會長期同時成為candidate且平分選票,導致長時間無法選主成功,這一段超時時間是隨機的,這保證了不會出現多個candidate周期性的分散選票,選票一定會收斂。

2.3.2 log replicate場景

put(x) 或 get(x) 操作僅可以由leader發起,如果沒有leader,則集群無法執行put或get。

log replication 分為兩步,一步為prepare,先確定有多少節點可以成功寫入,第二步為confirm,當然在用戶端,這兩步一起會封裝為一個put(x)操作,僅當兩步都成功才返回成功。

圖片

如圖,日誌複製snapshot, 這幅圖中可以看出n1.至少有三台機器遞交的才算遞交成功,n2.日誌可以落後,但絕不會出現中間不一致

圖片

圖1:request請求後在leader節點寫入,此時leader節點為uncommited狀態,put請求處於等待

圖片

圖2:由一次心跳後,子節點紛紛寫入,由於心跳還沒傳回主節點,主節點為uncommitted狀態,put請求仍在等待

圖片

圖3:RPC傳回後,代表著prepared成功了,主節點發送commit請求給子節點,注意這個瞬間微妙的點在於,子節點雖然還沒接受到committed信息,但子節點已經把記錄寫入到磁碟了,也就是處於重啟不會丟棄的狀態,put請求返回

圖片

圖4:在第二次心跳後,所有子節點都已知持久化狀態

和日誌複製機制有關的選舉限制:

  • 在一些一致性演算法中,例如:Viewstamped Replication,即使一開始沒有包含全部已提交的條目也可以被選為領導人。這些演算法都有一些另外的機制來保證找到丟失的條目並將它們傳輸給新的領導人,這個過程要麼在選舉過程中完成,要麼在選舉之後立即開始。不幸的是,這種方式大大增加了複雜性。

  • Raft 使用了一種更簡單的方式來保證:也就是日誌落後的候選人,無法被選中為Leader,這其實大大減小了選舉和日誌複製的相關性,簡化了raft的演算法理解難度。nn

和日誌複製機制有關的原則:

  • 如果在不同日誌中的兩個條目有著相同的索引和任期號,則它們所存儲的命令是相同的。

  • 如果在不同日誌中的兩個條目有著相同的索引和任期號,則它們之間的所有條目都是完全一樣的。

這兩個原則有助於在選舉時減少不一樣條目的檢索和對比。

3.一個混合場景的講解

在3中,會分析構造混合了leader election + log replication + fatal error的場景,有助於通過場景分析來深化理解raft協議:

3.1. 場景1,replication log落後的節點,無法獲得leader權

圖片

圖1:在s3成為leader並寫入多條log後,s3,s4掛掉,重新進行選主的場景(s1,s2是新加入的節點,在日誌上落後)

如圖所示,在這種場景下,由於節點s1,s2本地沒有持久化任何日誌,所以節點s1,s2無法獲得s5的選票,所以s1或s2永遠無法獲得leader角色。這種場景下,s5最慢會在2*心跳時間獲得leader權。

在s5獲得leader後,會和s1,s2追平持久化的日誌:

圖片

這個場景下,如果s4重新上線,則會變成如下:

圖片

在對這個新集群進行一次append後,集群的日誌變成如下:

圖片

該圖示揭示了在找到最近一次索引相同的日誌後,leader節點的committed log 覆蓋了s4的uncommitted log

4. 資料推薦

raft一個非常友好的點,就是提供了一個可以自己模擬協議發生以及各種請求的前端開源項目,該項目就嵌入在raft協議介紹主頁中,有興趣的可以模仿一下:Raft Consensus Algorithm

另外,raft還有一個圖文並茂,帶有動畫的介紹ppt,懶得長篇看文字的可以閱讀下這個:Raft

相信在看完以上兩個資料後,有一定基礎的碼農已經可以建立對raft的全方位理解了。
推薦閱讀:

事件和時間:Time, Clocks, and the Ordering of Events in a Distributed System 讀後感
小議分散式系統的一致性模型
state machine replication vs primary backup system
一致性, 兩階段提交和事務提交的發展史(譯)
關於一致性協議的一些對比和總結

TAG:分布式一致性 |