一致性算法RAFT詳解


原帖地址:http://www.solinx.co/archives/415?utm_source=tuicool&utm_medium=referral
一致性算法Raft詳解背景
  熟悉或了解分布性系統的開發者都字段一致性算法的重要性,Paxos一致性算法從90年提出到現在已經有二十幾年了,而Paxos流程太過於繁雜實現起來也比較復雜,可能也是以為過於復雜 現在我聽說過比較出名使用到Paxos的也就只是Chubby、libpaxos,搜了下發現Keyspace、BerkeleyDB數據庫中也使用了該算法作為數據的一致性同步,雖然現在很廣泛使用的Zookeeper也是基於Paxos算法來實現,但是Zookeeper使用的ZAB(Zookeeper Atomic Broadcast)協議對Paxos進行了很多的改進與優化,算法復雜我想會是制約他發展的一個重要原因;說了這么多只是為了要引出本篇文章的主角Raft一致性算法,沒錯Raft就是在這個背景下誕生的,文章開頭也說到了Paxos最大的問題就是復雜,Raft一致性算法就是比Paxos簡單又能實現Paxos所解決的問題的一致性算法。
  Raft是斯坦福的Diego Ongaro、John Ousterhout兩個人以易懂(Understandability)為目標設計的一致性算法,在2013年發布了論文:《In Search of an Understandable Consensus Algorithm》從2013年發布到現在不過只有兩年,到現在已經有了十多種語言的Raft算法實現框架,較為出名的有etcd,Google的Kubernetes也是用了etcd作為他的服務發現框架;由此可見易懂性是多么的重要。
Raft概述
  與Paxos不同Raft強調的是易懂(Understandability),Raft和Paxos一樣只要保證n/2+1節點正常就能夠提供服務;眾所周知但問題較為復雜時可以把問題分解為幾個小問題來處理,Raft也使用了分而治之的思想把算法流程分為三個子問題:選舉(Leader election)、日志復制(Log replication)、安全性(Safety)三個子問題;這里先簡單介紹下Raft的流程;
  Raft開始時在集群中選舉出Leader負責日志復制的管理,Leader接受來自客戶端的事務請求(日志),並將它們復制給集群的其他節點,然后負責通知集群中其他節點提交日志,Leader負責保證其他節點與他的日志同步,當Leader宕掉后集群其他節點會發起選舉選出新的Leader;
Raft詳解
1、角色
  Raft把集群中的節點分為三種狀態:Leader、 Follower 、Candidate,理所當然每種狀態負責的任務也是不一樣的,Raft運行時提供服務的時候只存在Leader與Follower兩種狀態;
  Leader(領導者):負責日志的同步管理,處理來自客戶端的請求,與Follower保持這heartBeat的聯系;
  Follower(追隨者):剛啟動時所有節點為Follower狀態,響應Leader的日志同步請求,響應Candidate的請求,把請求到Follower的事務轉發給Leader;
  Candidate(候選者):負責選舉投票,Raft剛啟動時由一個節點從Follower轉為Candidate發起選舉,選舉出Leader后從Candidate轉為Leader狀態;
2、Term
  在Raft中使用了一個可以理解為周期(第幾屆、任期)的概念,用Term作為一個周期,每個Term都是一個連續遞增的編號,每一輪選舉都是一個Term周期,在一個Term中只能產生一個Leader;先簡單描述下Term的變化流程: Raft開始時所有Follower的Term為1,其中一個Follower邏輯時鍾到期后轉換為Candidate,Term加1這是Term為2(任期),然后開始選舉,這時候有幾種情況會使Term發生改變:
  1:如果當前Term為2的任期內沒有選舉出Leader或出現異常,則Term遞增,開始新一任期選舉
  2:當這輪Term為2的周期選舉出Leader后,過后Leader宕掉了,然后其他Follower轉為Candidate,Term遞增,開始新一任期選舉
  3:當Leader或Candidate發現自己的Term比別的Follower小時Leader或Candidate將轉為Follower,Term遞增
  4:當Follower的Term比別的Term小時Follower也將更新Term保持與其他Follower一致;
  可以說每次Term的遞增都將發生新一輪的選舉,Raft保證一個Term只有一個Leader,在Raft正常運轉中所有的節點的Term都是一致的,如果節點不發生故障一個Term(任期)會一直保持下去,當某節點收到的請求中Term比當前Term小時則拒絕該請求;
3、選舉(Election)
  Raft的選舉由定時器來觸發,每個節點的選舉定時器時間都是不一樣的,開始時狀態都為Follower某個節點定時器觸發選舉后Term遞增,狀態由Follower轉為Candidate,向其他節點發起RequestVote RPC請求,這時候有三種可能的情況發生:
  1:該RequestVote請求接收到n/2+1(過半數)個節點的投票,從Candidate轉為Leader,向其他節點發送heartBeat以保持Leader的正常運轉
  2:在此期間如果收到其他節點發送過來的AppendEntries RPC請求,如該節點的Term大則當前節點轉為Follower,否則保持Candidate拒絕該請求
  3:Election timeout發生則Term遞增,重新發起選舉
  在一個Term期間每個節點只能投票一次,所以當有多個Candidate存在時就會出現每個Candidate發起的選舉都存在接收到的投票數都不過半的問題,這時每個Candidate都將Term遞增、重啟定時器並重新發起選舉,由於每個節點中定時器的時間都是隨機的,所以就不會多次存在有多個Candidate同時發起投票的問題。
  有這么幾種情況會發起選舉,1:Raft初次啟動,不存在Leader,發起選舉;2:Leader宕機或Follower沒有接收到Leader的heartBeat,發生election timeout從而發起選舉;


4、日志復制(Log Replication)
  日志復制(Log Replication)主要作用是用於保證節點的一致性,這階段所做的操作也是為了保證一致性與高可用性;當Leader選舉出來后便開始負責客戶端的請求,所有事務(更新操作)請求都必須先經過Leader處理,這些事務請求或說成命令也就是這里說的日志,我們都知道要保證節點的一致性就要保證每個節點都按順序執行相同的操作序列,日志復制(Log Replication)就是為了保證執行相同的操作序列所做的工作;在Raft中當接收到客戶端的日志(事務請求)后先把該日志追加到本地的Log中,然后通過heartbeat把該Entry同步給其他Follower,Follower接收到日志后記錄日志然后向Leader發送ACK,當Leader收到大多數(n/2+1)Follower的ACK信息后將該日志設置為已提交並追加到本地磁盤中,通知客戶端並在下個heartbeat中Leader將通知所有的Follower將該日志存儲在自己的本地磁盤中。
5、安全性(Safety)
  安全性是用於保證每個節點都執行相同序列的安全機制,如當某個Follower在當前Leader commit Log時變得不可用了,稍后可能該Follower又會倍選舉為Leader,這時新Leader可能會用新的Log覆蓋先前已committed的Log,這就是導致節點執行不同序列;Safety就是用於保證選舉出來的Leader一定包含先前 commited Log的機制;
  選舉安全性(Election Safety)
  每個Term只能選舉出一個Leader
  Leader完整性(Leader Completeness)
  這里所說的完整性是指Leader日志的完整性,當Log在Term1被Commit后,那么以后Term2、Term3…等的Leader必須包含該Log;Raft在選舉階段就使用Term的判斷用於保證完整性:當請求投票的該Candidate的Term較大或Term相同Index更大則投票,否則拒絕該請求;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM