raft
1. 特點(diǎn)
- strong leader
raft是強(qiáng)leader算法,日志只從leader分發(fā),使理解更容易 - leader election
raft節(jié)點(diǎn)隨機(jī)時間選舉leader,可以快速簡單的處理沖突 - membership changes
允許集群在配置更改期間繼續(xù)正常運(yùn)行
2. 一致性算法的典型屬性
- 永遠(yuǎn)不返回錯誤結(jié)果
- 只要半數(shù)以上節(jié)點(diǎn)可用,就可以正常工作
- 它們不依賴于時間來確保日志的一致性:錯誤的時鐘和極端的消息延遲在最壞的情況下會導(dǎo)致可用性問題
- 一般情況下只要超過半數(shù)節(jié)點(diǎn)通過,就可以成功返回
3 raft概況
同步狀態(tài)機(jī)架構(gòu)圖
3.1 State
3.1.1 所有節(jié)點(diǎn)都會持久化的狀態(tài)信息
(響應(yīng)rpc前會先持久化)
- currentTerm
server的最新term(初始化為0,逐個遞增) - votedFor
在當(dāng)前term中,收到的vote的candidateId - log[]
log entries
每個entry包含state machine 的操作命令以及收到entry時的term信息
3.1.2 所有節(jié)點(diǎn)都會保存的非持久化信息
- commitIndex
最新的log entry index 提交編號(初始化為0,單調(diào)遞增) - lastApplied
最新的應(yīng)用log entry編號(初始化為0,單調(diào)遞增)
3.1.3 leaders才會保存的非持久化信息
(選舉后會重新初始化)
- nextIndex[]
要發(fā)送給各個server的log entry的編號(初始化為leader的 last log index+1) - matchIndex[]
每個節(jié)點(diǎn)leader已知已經(jīng)同步的log entry 最大 index (初始化為0,單調(diào)遞增)
3.2 AppendEntries RPC
(leader同步log entry,以及心跳相關(guān)操作)
3.2.1 Arguments
- term
leader`s term - leaderId
- prevLogIndex
緊接在新日志項(xiàng)之前的日志項(xiàng)的索引 - prevLogTerm
prevLogIndex 對應(yīng)的term - entries[]
需要持久化的log entry(心跳時為空,同步時為了提升效率也可以一次同步多條 log entry) - leaderCommit
leader`s commitIndex
3.2.2 Results
- term
當(dāng)前的term,方便leader紀(jì)錄保存 - success
follower如果已經(jīng)同步 prevLogIndex and prevLogTerm的log entry則返回true
3.2.3 Receiver implementation
- 如果term < currentTerm 返回 false
- 如果在prevLogIndex對應(yīng)的log中的term不等于prevLogTerm則返回false
- 如果已經(jīng)存在的entry中與新的log entry沖突(index相同,但是term不同),則刪除已經(jīng)存在的entry,應(yīng)用新的log entry
- 如果沒有新log對應(yīng)的index,則直接append新增的entries
- 如果 leaderCommit > commitIndex 則設(shè)置 set commitIndex =
min(leaderCommit, index of last new entry)
3.3 RequestVote RPC
(candidates 獲取 選舉信息)
3.3.1 arguments
- term
candidate`s term - candidateId
發(fā)起選舉的candidateId - lastLogIndex
candidate的最新的log erntry的 index - lastLogTerm
candidate的最新的log entry 的 term
3.3.2 results
- term
當(dāng)前的term,方便condidate更新各個節(jié)點(diǎn)的term信息 - voteGranted
如果同意選舉 condidate 則返回true
3.3.3 Receiver implementation(返回說明)
- 如果term 小于currentTerm則返回false
- 如果votedFor是null或者candidateId,并且candidate’s log同步情況不晚于receiver的log,則返回true
3.4 Rules for Servers
3.4.1 All Servers
- 如果 commitIndex > lastApplied
增加lastApplied,并應(yīng)用log[lastApplied] - 如果 request or response 包含 term T > currentTerm
則 set currentTerm = T, convert to follower
3.4.2 Followers
- Respond to RPCs from candidates and leaders
- 如果在election timeout時間內(nèi)沒有收到當(dāng)前l(fā)eader發(fā)送的AppendEntries RPC調(diào)用或者candidate的選舉請求,則轉(zhuǎn)為candidate
3.4.3 Candidates
- 關(guān)于轉(zhuǎn)變?yōu)镃andidate角色后發(fā)起選舉
- 增加currentTerm
- 選舉自己為leader
- 重置election timer
- 向所有節(jié)點(diǎn)發(fā)送選舉請求RPC
- 如果過半節(jié)點(diǎn)同意選舉請求,則轉(zhuǎn)換為leader角色
- 如果收到新leader的AppendEntries則轉(zhuǎn)為follower角色
- 如果超過 election timeout 則開啟新一輪的選舉
3.4.4 Leaders
- 選舉為leader
發(fā)送初始AppendEntries RPCs (heartbeat) 給所有節(jié)點(diǎn),在整個空閑期都發(fā)送,防止有節(jié)點(diǎn)沒收到heartbeat,發(fā)起選舉 - 收到客戶端命令時
在本地 append entry log
等待更新到 state machine后,才返回給客戶端 - 如果 last log index ≥ nextIndex for a follower
發(fā)送起始于nextIndex的 AppendEntries RPC with log entries- 如果成功,則更新對應(yīng)follower的nextIndex and matchIndex
- 如果因?yàn)閘og不一致導(dǎo)致失敗,則decrement nextIndex and retry
- 如果大部分節(jié)點(diǎn)的matchIndex[i] ≥ N, log[N].term == currentTerm 并且 N > commitIndex 則set commitIndex = N
3.5 raft會保證整個生命周期如下的規(guī)則
- election safety
在同一個term下,最多選舉出一個leader - leader append-only
leader只會添加log,不會有覆蓋或著刪除操作 - log matching
如果兩個log具有相同的term和index,則之前的所有l(wèi)og都會相同 - leader completeness
如果一個log entry在一個term下被提交,則任何leader(如果發(fā)生leader選舉)在之后的term中都會包含此log entry - state machine safety
如果server已經(jīng)應(yīng)用某個index下的log entry到state machine,不會有其他的server在相同的index下應(yīng)用不同的log entry
3.6 server節(jié)點(diǎn)角色
4 raft一致性算法詳細(xì)介紹
raft算法分為三個獨(dú)立的部分:
- Leader election
如果當(dāng)前的leader fails時,必須要選舉出一個leader - Log replication
leader接受客戶端的命令,并且同步到整個集群,其他節(jié)點(diǎn)必須與leader數(shù)據(jù)保持一致 - Safety
raft主要確保state machine的可靠性:如果任何一個server應(yīng)用一條log entry到 state machine,就確保不會在相同的index下應(yīng)用其他log
以下列出論文中的條目,方便有個全局印象
- 4.1 Raft basics
- 4.2 Leader election
- 4.3 Log replication
- 4.4 Safety
- 4.4.1 Election restriction
- 4.4.2 Committing entries from previous terms
- 4.4.3 Safety argument
- 4.5 Follower and candidate crashes
- 4.6 Timing and availability
以下分別詳細(xì)介紹
4.1 Raft basics
一般一個raft集群包含5個節(jié)點(diǎn)(可以允許兩個節(jié)點(diǎn)異常),任何時間點(diǎn)下server只會是 leader,follower或者candidate中的一個角色.正常運(yùn)行情況下,只會有一個leader,其他節(jié)點(diǎn)都為follower. follower只會被動接收leader和candidate的request而不會主動發(fā)送請求.leader處理所有客戶端的請求(如果client連接flolower,會轉(zhuǎn)接給leader). candidate用于選舉leader時的中間狀態(tài).
raft會把時間劃分到任意長度的term,term是連續(xù)遞增編號的,最開始的term會先發(fā)起選舉,如果有candidate贏得選舉,則會成為leader,如果選舉沖突,則會在下一個term重新選舉.raft確保在同一個term下,最多有一個leader
term就是raft里的邏輯時鐘,每個server都會保存一個當(dāng)前term值,term會隨著時間遞增.current term信息會在集群內(nèi)不斷交換,如果一個server的current term比其他server小,會更新到較大的那個值,如果一個candidate或leader發(fā)現(xiàn)自己的term是過期的,則會降級為follower,如果server收到term老舊的request,server會拒絕響應(yīng).
raft使用rpc進(jìn)行通信,基本的raft算法只需要兩種rpc服務(wù),RequestVote rpc是在選舉期間由候選人發(fā)起,Append-Entries RPCs 則是由leader發(fā)起的用于replicate log entries 和 heartbeat. raft還有第三種rpc服務(wù)(InstallSnapshot RPC),用于在服務(wù)器之間傳輸快照
4.2 Leader election
raft通過heartbeat機(jī)制觸發(fā)選舉.server啟動時,會作為followers角色,并且只要能夠收到來自leader或candidate有效的rpc請求,server會一直保持followers角色,如果超過election timeout沒有收到heartbeat, 則會認(rèn)為當(dāng)前沒有可用的leader節(jié)點(diǎn),并會發(fā)起選舉.
要發(fā)起選舉,follower會先增加自己的term并且轉(zhuǎn)變?yōu)閏andidate角色,選舉自己為leader,并且并發(fā)的向其他節(jié)點(diǎn)發(fā)起 RequestVote RPCs ,結(jié)果會有三種:
1 自己贏得選舉成為leader
2 其他節(jié)點(diǎn)贏得選舉成為leadder
3 沒有節(jié)點(diǎn)贏得選舉
下面分別探討三種情況
- 如果大多數(shù)server選舉的candidate會成為leader,每個server在同一個term下最多給一個server投票(誰先發(fā)起RequestVote,選舉誰),candidate成為leader后,發(fā)送heartbeat給各個節(jié)點(diǎn),防止新的選舉發(fā)生
- candidate在等待選舉結(jié)果時,如果收到leader發(fā)送的AppendEntries RPC,并且leader’s term (included in its RPC) 不低于 candidate’s current term,則認(rèn)為leader是合法的,自己降級為follower,如果leader的term低于自己的current term,則會忽略,繼續(xù)保持 candidate 狀態(tài)
- 如果多個candidate發(fā)起選舉,并且都沒有能贏得大多數(shù)的投票,則會等待選舉超時后,增加term,發(fā)起新一輪的選舉.
raft使用隨機(jī)的 election timeouts 來避免選舉沖突,一般為150–300ms范圍內(nèi)的隨機(jī)值.相同的機(jī)制用于處理分裂投票道偷。每個候選人在選舉開始時重新啟動隨機(jī)化的選舉超時赋朦,并在開始下一次選舉前等待超時時間的流逝;這減少了在新選舉中再次出現(xiàn)分裂投票的可能性。
4.3 Log replication
leader被選舉出來后,就可以響應(yīng)客戶端的請求.一個client的請求包含一個replicated state machines要執(zhí)行的命令.leader會將命令添加到log , 然后并發(fā)給每個節(jié)點(diǎn)的發(fā)起 AppendEntries RPCs,entry被safely復(fù)制后,leader應(yīng)用entry到state machine中,并返回成功給client.如果followers crash或響應(yīng)慢或者網(wǎng)絡(luò)有問題,leader會不定期重新發(fā)送 Append-Entries RPCs (即使leader 已經(jīng)responded client),直到followers最終存儲所有的log.
log的組織形式如下圖:
每個log entry包含一個state machine命令以及l(fā)eader接收entry的term編號.log entries中的term可以用來探測不一致.每個log entry還有一個index編號,確認(rèn)在log里的位置.
leader決定何時應(yīng)用log entry到state machine,成為一個提交了的log entry. raft確保已經(jīng)提交的erntry最終會被所有節(jié)點(diǎn)應(yīng)用到可用的state machines.一旦leader將log etnry同步到大多數(shù)節(jié)點(diǎn),該條log就被提交.
raft會維護(hù)如下屬性:
- 如果兩個log具有相同的index和term,則它們存儲的命令相同
-
如果兩個log具有相同的index和term,則它們前面的log都相同
首先leader在每個term的每個log index下最多創(chuàng)建一個entry,并且此后不會在改變,來確保第一個屬性
其次通過AppendEntries簡單的一致性檢查來確保第二個屬性,leader發(fā)送的AppendEntries RPC中,會包含上一條log entry的index and term ,如果follower沒有找到相同index,term的log,則會refuse新的entry.一致性檢查作為一個歸納步驟:日志的初始空狀態(tài)滿足日志匹配屬性惕蹄,一致性檢查在擴(kuò)展日志時保留日志匹配屬性闭专。因此,每當(dāng)AppendEntries 成功返回時,leader就知道follower的日志與它自己通過新條目的日志是相同的蜻展。
正確情況下,leader和followers是一致的,AppendEntries的一致性檢查也不會出錯.但是leader可能會導(dǎo)致不一致情況(old leader可能沒有將所有的entry復(fù)制到所有節(jié)點(diǎn)).如下圖所示,因?yàn)橐幌盗械膌eader和follower的 crash,導(dǎo)致數(shù)據(jù)不一致,follower可能相比于leader多或者少數(shù)據(jù).
image.png
raft算法中,通過強(qiáng)制follower同步leader的log來處理不一致問題,即follower與leader沖突的log會用leader的log覆蓋(下一節(jié)會探討這樣做的可行性)
為了修復(fù)不一致數(shù)據(jù),leader必須找到最后一個兩者都agree的log,刪除follower此后的日志,發(fā)送leader此后的log到follower(這些都在AppendEntries RPCs中處理).leader 維護(hù)了 每個folloer的 nextIndex(要發(fā)送的下一條log的index). 一旦選舉出leader后,會初始化所有follower的nextIndex為leader的最后一條log index.如果follower與leader不一致, AppendEntries check則會返回錯誤,leader收到錯誤信息會減少nextIndex并且重試AppendEntries RPC,最終nextIndex會找到leader和follower一致的點(diǎn),然后在刪除沖突entry并且同步leader的log后,AppendEntries返回成功,并且follower與leader達(dá)到一致狀態(tài).
4.4 Safety
本節(jié)通過添加對哪些服務(wù)器可以被選為leader的限制來完成Raft算法。這個限制確保任何給定期限的leader獲得在以前期限中提交的所有條目邀摆。最后纵顾,我們給出了Leader完備性的一個證明圖,并展示了它是如何導(dǎo)致復(fù)制狀態(tài)機(jī)的正確行為的栋盹。
4.4.1 Election restriction
在任何基于領(lǐng)導(dǎo)的協(xié)商一致算法中施逾,領(lǐng)導(dǎo)最終必須存儲所有提交的日志條目。在一些協(xié)商一致的算法中例获,比如Viewstamped Replication[22]汉额,可以選出一個leader,即使它最初不包含所有提交的條目榨汤。這些算法包含額外的機(jī)制來識別缺失的條目蠕搜,并在選舉過程中或選舉后不久將其發(fā)送給新領(lǐng)導(dǎo)人。不幸的是件余,這導(dǎo)致相當(dāng)多的額外機(jī)械和復(fù)雜性讥脐。Raft使用了一種更簡單的方法,它保證所有來自previousterm的提交條目從每個新領(lǐng)導(dǎo)者當(dāng)選的那一刻起就存在啼器,而不需要將這些條目傳遞給領(lǐng)導(dǎo)者旬渠。這意味著日志條目只在一個方向上流動,即從leader到follower端壳。
raft通過在選舉中添加限制來確保只有包含所有已經(jīng)提交的log的節(jié)點(diǎn)才能選舉成功.因?yàn)橐鄶?shù)節(jié)點(diǎn)選舉才能成為leader,至少在其中一個節(jié)點(diǎn)包含所有提交的entry,進(jìn)而,如果candidate比大多數(shù)節(jié)點(diǎn)的log都up-to-date則可以確保該candidate包含所有已經(jīng)提交的信息(如果voter比candidate的log更up-to-date則不會選舉它)
raft通過比較最后一條entry的index和term來判斷哪個更加up-to-date,如果兩個log term不相同,則term較大的更up-to-date,如果term相同,則log越長的越up-to-date
4.4.2 Committing entries from previous terms
舊leader crash之后,新的leader會嘗試在之前的基礎(chǔ)上完成entry的復(fù)制,但是即使大部分節(jié)點(diǎn)同步了一個entry,也不能確定確認(rèn)entry已經(jīng)提交,下圖給出了一種大多數(shù)節(jié)點(diǎn)已經(jīng)同步log的情況下,依然被新leader覆蓋掉的情況(term是基于時間生成的)
為了避免上面的情況,raft不會根據(jù)已經(jīng)同步的replicas個數(shù)來確認(rèn)是提交.只有l(wèi)eader當(dāng)前term的提交才會根據(jù)是否有大多數(shù)節(jié)點(diǎn)同步,只要當(dāng)前term的entry被提交,則所有之前的entry也可以通過 Log Matching Property來間接保證提交.
4.5 Safety argument
以下通過反證法,證明raft能夠保證數(shù)據(jù)完整性.
假設(shè)leader(leader_T)提交 term T log,但是term T log沒有在新的term的leader(leader_U U>T)中保存,則可以作出如下推測:
- 在 leader_U選舉時肯定沒有 log T
- leader_T 同步了log T 到大部分機(jī)器上, 而leader_U是被大部分節(jié)點(diǎn)選舉出來,則最少有一個voter(voter_special)包含log T
- voter_special在選舉leader_U前,肯定接收到了leader_T的committed entry,否則會
rejected the AppendEntries request from leader_T - voter_special在選舉leader_U時依然會保存有l(wèi)og T
- voter_special選舉了leader_U, 所以 leader_U的log必須不比voter_special舊,因此只會有如下兩種情況
- voter_special和leader_U 最新的term相同, 則leader_U應(yīng)該不少于voter_special的log,應(yīng)該包含 log T
- 如果leader_U的log term 比 voter_special大,則之前l(fā)eader_U在同步最新的term時會保證包含所有之前term的數(shù)據(jù)( by the Log Matching Property),即包含 log T
最后,raft要求server按照 log index順序應(yīng)用 log entry,與 State Machine Safety Property 相結(jié)合,共同確保所有節(jié)點(diǎn)的state machines會按照相同的順序應(yīng)用log
4.6 Follower and candidate crashes
如果一個follower或者candidate crash,那么后續(xù)的RequestVote和AppendEntries RPCs 就會失敗,raft會不定期的重試,如果crash的節(jié)點(diǎn)重新啟動,rpc會成功.如果一個server在完成rpc請求,但是在返回成功前crash,則會在重啟后收到一個相同的rpc請求,因?yàn)閞aft的rpc請求是冪等的,所以不用做特殊處理.例如,如果follower收到的AppendEntries請求里的log與當(dāng)前l(fā)og包含一樣的內(nèi)容,節(jié)點(diǎn)會忽略這些entries
4.7 Timing and availability
raft集群必須要滿足如下時間關(guān)系,否則無法正常選主,對外提供服務(wù):
broadcastTime ? electionTimeout ? MTBF
其中:
- broadcastTime 為發(fā)送rpc并且收到回應(yīng)的平均時間
- electionTimeout 選舉超時時間
- MTBF 兩個節(jié)點(diǎn)crash間隔的平均時間
一般 broadcastTime 為 0.5~20ms
electionTimeout 因此在10~500ms之間
MTBF一般為幾個月
5 Cluster membership changes
配置變更時,如果只是簡單的逐個變更,則可能會有同一個term下,兩個主的危險,如下圖所示:
為了避免上面的問題,raft使用兩階段提交來變更配置,首先切換為變更配置狀態(tài)( joint consensus),joint consensus 提交后,集群使用新的配置,joint consensus combines both the old and new configurations:
- log entry會被同步到新舊配置的所有節(jié)點(diǎn)
- 新舊配置中的任何一個節(jié)點(diǎn)都可能作為leader
-
選舉或著entry的提交需要經(jīng)過新舊配置所有節(jié)點(diǎn)的大多數(shù)通過
joint consensus 允許允許各個服務(wù)器在不同的時間在不同的配置之間進(jìn)行轉(zhuǎn)換告丢,而不會出現(xiàn)安全隱患。此外损谦,允許集群在整個配置更改期間繼續(xù)為客戶端請求提供服務(wù)岖免。
Cluster configurations 的存儲和同步使用特殊的一種log entry,下圖描述了configuration change process
image.png
leader收到 Cold to Cnew的請求時,會存儲configuration 信息為 joint consensus log entry,并且同步到其他節(jié)點(diǎn),一旦server添加了new configuration entry 到log,未來的decision都會使用這個configuration(server總是使用最新的configuration,不管提交與否),這就意味著,leader會使用Cold,new 來判斷l(xiāng)og entry for Cold,new 是否提交,如果leader crash,新leader的配置可能為 Cold or Cold,new任何情況下Cnew 都無法作出單方面的decisions
一旦Cold,new提交之后,無論 Cold 或著 Cnew 都無法獨(dú)立的作出decision,Leader Completeness Property 也確保了只有包含 Cold,new log entry 的節(jié)點(diǎn)才會被選舉為leader.此時創(chuàng)建一個Cnew的log entry并同步到其他節(jié)點(diǎn)是安全可靠的,其他節(jié)點(diǎn)同樣一同步到Cnew就生效.只要Cnew被提交,Cold就無關(guān)緊要,Cnew中沒用的節(jié)點(diǎn)就可以shutdown,如上圖所示,Cnew和Cold沒有重疊的時間做decision,因此可以確保安全.
此外,新增節(jié)點(diǎn)沒有初始化的數(shù)據(jù),可能需要很長時間才能同步數(shù)據(jù),無法提交新的log.未了避免這段 availability gaps,raft引入一個額外的階段( non-voting members, leader只同步log entry到該節(jié)點(diǎn),但是not considered for majorities,直到同步完成).
第二點(diǎn),舊配置的leader可能在新配置中被排除,這種情況下只要提交了Cnew,就立刻降級(變?yōu)?follower state),這就有一個階段會是leader管理一個不把自己count到majorities 的時間段.Cnew提交后(這之后new configuration才能夠operate independently,之前只有Cold的節(jié)點(diǎn)才能選舉為leader),才會發(fā)生leader的轉(zhuǎn)換.
第三種情況,可能被刪除的節(jié)點(diǎn)依然存活,因?yàn)椴辉贑new中,不會收到heatbeat,因此會不斷的發(fā)起選舉,損耗性能.為了處理這種情況,節(jié)點(diǎn)如果確信已經(jīng)有l(wèi)eader正常運(yùn)行時會忽略 RequestVote RPCs.此外,如果一個server在minimum election timeout的時間內(nèi)收到當(dāng)前l(fā)eader的 RequestVote RPC也會被忽略,但是這個不會影響正常的選舉,因?yàn)檎5倪x舉流程至少要等一個minimum election timeout
6 log compaction
raft的log會逐漸增長,需要做壓縮清理,Snapshotting是一種最簡便的方式,下圖展示了snapshots的基本流程.
每個server獨(dú)立的獲取快照,覆蓋已經(jīng)提交的log,主要的工作就是state machine 將當(dāng)前狀態(tài)寫入快照.raft快照中還會包含一部分的metadata,主要為最后一條log的index和term信息,主要是用于AppendEntries的一致性檢查.此外,為了方便 membership changes, snapshot還會包含最新的configuration信息.一旦server完成了snapshot,就可以把之前的log entry和之前的snapshot都給清理掉.
雖然server會各自做snapshot,但是leader還是會偶爾發(fā)送snapshots到有延遲的節(jié)點(diǎn)(發(fā)生在follower延遲較高,leader把它所需要的next log entry已經(jīng)清理的情況下,一般發(fā)生在新加入節(jié)點(diǎn)的情況).
leader會有InstallSnapshot RPC來發(fā)送snapshots給followers,如下圖所示:
follower收到InstallSnapshot RPC后必須要決定怎么處理現(xiàn)存的log entry.一般是收到的InstallSnapshot RPC中日志比server的新,則server會將之前的log清理掉,如果是當(dāng)前的log已經(jīng)比Snapshot 更新,則將沖突的部分覆蓋清理掉,更新的部分則保留.
還有另外兩個影響快照的問題岳颇。首先,服務(wù)器必須決定何時進(jìn)行快照颅湘。如果服務(wù)器快照太頻繁话侧,就會浪費(fèi)磁盤帶寬和能量;如果快照太不頻繁,就有耗盡存儲容量的風(fēng)險闯参,還會增加重新啟動時重播日志所需的時間瞻鹏。一個簡單的策略是在日志達(dá)到固定大小(以字節(jié)為單位)時捕獲快照。如果將此大小設(shè)置為比快照的預(yù)期大小大得多鹿寨,那么用于快照的磁盤帶寬開銷將很小新博。
第二個問題是,編寫快照可能會花費(fèi)大量時間脚草,我們不希望這會延遲正常的操作赫悄。解決方案是使用即寫即拷技術(shù),這樣就可以接受新的更新馏慨,而不會影響正在寫入的快照埂淮。例如,使用 functional data structures構(gòu)建的state machines 自然支持這一點(diǎn)熏纯⊥耄或者粤策,操作系統(tǒng)的寫時復(fù)制支持(例如樟澜,Linux上的fork)可以用來創(chuàng)建整個狀態(tài)機(jī)的內(nèi)存快照(我們的實(shí)現(xiàn)使用這種方法)。
7 Client interaction
如果client發(fā)送請求到raft集群后,raft已經(jīng)提交,但是leader在返回response給client前crash,則client會任務(wù)沒有提交成功,則會重新在新的leader上再此執(zhí)行導(dǎo)致錯誤.因此client會給每個command一個唯一的編號,state machine在處理請求時也會保存每個client對應(yīng)的編號,如果收到command的編號已經(jīng)執(zhí)行過,則會直接返回,防止再次執(zhí)行.
在做讀操作的時候因?yàn)闆]有寫操作,client連接的leader時是無法確認(rèn)這個leader是否已經(jīng)被排除,已經(jīng)選舉出來新的leader,因此需要額外工作,確保數(shù)據(jù)是否為最新.
- 響應(yīng)請求前,leader會提交一個blank no-op entry log 來開始一個term,確保當(dāng)前l(fā)eader是正常的
- raft會先檢查是否大多數(shù)節(jié)點(diǎn)的heartbeta message正常響應(yīng),之后才會返回結(jié)果