分布式事务与一致性算法Paxos amp; raft amp; zab
要想數(shù)據(jù)高可用,就得寫多份數(shù)據(jù)
寫多分?jǐn)?shù)據(jù)就會(huì)導(dǎo)致數(shù)據(jù)一致性問(wèn)題
數(shù)據(jù)一致性問(wèn)題會(huì)引起性能問(wèn)題
2.一致性模型
弱一致性
最終一致性(一段時(shí)間達(dá)到一致性)
強(qiáng)一致
1、2 異步冗余;3是同步冗余
3.? 擴(kuò)展服務(wù)的方案
數(shù)據(jù)分區(qū): uid % 16
數(shù)據(jù)鏡像:讓多有的服務(wù)器都有相同的數(shù)據(jù),提供相當(dāng)?shù)姆?wù)(冗余存儲(chǔ),一般3份為好)
4.兩種方案的事務(wù)問(wèn)題
A向B匯錢,兩個(gè)用戶不在一個(gè)服務(wù)器上
鏡像:在不同的服務(wù)器上對(duì)同一數(shù)據(jù)的寫操作如何保證一致性。?
5. 解決一致性事務(wù)問(wèn)題的技術(shù)
1. Master -Slave
讀寫請(qǐng)求由Master負(fù)責(zé)
寫請(qǐng)求寫到Master后,由Master同步到Slave上
由Master push or Slave pull
通常是由Slave 周期性來(lái)pull,所以是最終一致性
問(wèn)題: 若在 pull 周期內(nèi)(不是期間?),master掛掉,那么會(huì)導(dǎo)致這個(gè)時(shí)間片內(nèi)的數(shù)據(jù)丟失
若不想讓數(shù)據(jù)丟掉,Slave 只能成為 ReadOnly方式等Master恢復(fù)
若容忍數(shù)據(jù)丟失,可以讓 Slave代替Master工作
如何保證強(qiáng)一致性?
Master 寫操作,寫完成功后,再寫 Slave,兩者成功后返回成功。若 Slave失敗,兩種方法
標(biāo)記 Slave 不可用報(bào)錯(cuò),并繼續(xù)服務(wù)(等恢復(fù)后,再同步Master的數(shù)據(jù),多個(gè)Slave少了一個(gè)而已)
回滾自己并返回失敗
2. Master-Master
數(shù)據(jù)同步一般是通過(guò) Master 間的異步完成,所以是最終一致
好處: 一臺(tái)Master掛掉,另外一臺(tái)照樣可以提供讀寫服務(wù)。當(dāng)數(shù)據(jù)沒(méi)有被賦值到別的Master上時(shí),數(shù)據(jù)會(huì)丟失。
對(duì)同一數(shù)據(jù)的處理問(wèn)題:Dynamo的Vector?Clock的設(shè)計(jì)(記錄數(shù)據(jù)的版本號(hào)和修改者),當(dāng)數(shù)據(jù)發(fā)生沖突時(shí),要開(kāi)發(fā)者自己來(lái)處理
3.兩階段提交? Two? Phase Commit?? _ 2PC
第一階段:針對(duì)準(zhǔn)備工作
協(xié)調(diào)者問(wèn)所有節(jié)點(diǎn)是否可以執(zhí)行提交
參與者開(kāi)始事務(wù),執(zhí)行準(zhǔn)備工作:鎖定資源(獲取鎖操作)
參與者響應(yīng)協(xié)調(diào)者,如果事務(wù)的準(zhǔn)備工作成功,則回應(yīng)"可以提交",否則,拒絕提交
第二階段:
若都響應(yīng)可以提交,則協(xié)調(diào)者項(xiàng)多有參與者發(fā)送正式提交的命令(更新值),參與者完成正式提交,釋放資源,回應(yīng)完成。協(xié)調(diào)者收到所有節(jié)點(diǎn)的完成響應(yīng)后結(jié)束這個(gè)全局事務(wù).。若參與者回應(yīng)拒絕提交,則協(xié)調(diào)者向所有的參與者發(fā)送回滾操作,并釋放資源,當(dāng)收到全部節(jié)點(diǎn)的回滾回應(yīng)后,取消全局事務(wù)
存在的問(wèn)題:若一個(gè)沒(méi)提交,就會(huì)進(jìn)行回滾
第一階段:若消息的傳遞未接收到,則需要協(xié)調(diào)者作超時(shí)處理,要么當(dāng)做失敗,要么重載
第二階段:若參與者的回應(yīng)超時(shí),要么重試,要么把那個(gè)參與者即為問(wèn)題節(jié)點(diǎn),提出整個(gè)集群
在第二階段中,參與者未收到協(xié)調(diào)者的指示(也許協(xié)調(diào)者掛掉),則所有參與者會(huì)進(jìn)入“不知所措” 的狀態(tài)(但是已經(jīng)鎖定了資源),所以引入了三段提交
4. 三段提交:把二段提交的第一階段 break 成了兩段
詢問(wèn)
鎖定資源(獲取鎖)
提交
核心理念:在詢問(wèn)的時(shí)候并不鎖定資源,除非所有人都同意了,才開(kāi)始鎖定
好處:當(dāng)發(fā)生了失敗或超時(shí)時(shí),三段提交可以繼續(xù)把狀態(tài)變?yōu)镃ommit 狀態(tài),而二段提交則不知所措?
5. Raxos 算法(少數(shù)服從多數(shù))
解決的問(wèn)題:在一個(gè)可能發(fā)生異常的分布式系統(tǒng)中如何就某個(gè)值達(dá)成一致,讓整個(gè)集群的節(jié)點(diǎn)對(duì)某個(gè)值的變更達(dá)成一致
任何一個(gè)節(jié)點(diǎn)都可以提出要修改某個(gè)數(shù)據(jù)的提案,是否通過(guò)這個(gè)提案取決于這個(gè)集群中是否有超過(guò)半數(shù)的節(jié)點(diǎn)同意(所以節(jié)點(diǎn)數(shù)總是單數(shù))—— 版本標(biāo)記。雖然一致性,但是只能對(duì)一個(gè)操作進(jìn)行操作啊??
當(dāng)一個(gè)Server接收到比當(dāng)前版本號(hào)小的提案時(shí),則拒絕。當(dāng)收到比當(dāng)前大的版本號(hào)的提案時(shí),則鎖定資源,進(jìn)行修改,返回OK.?? 也就是說(shuō)收到超過(guò)一半的最大版本的提案才算成功。
核心思想:
在搶占式訪問(wèn)權(quán)的基礎(chǔ)上引入多個(gè)acceptor,也就是說(shuō)當(dāng)一個(gè)版本號(hào)更大的提案可以剝奪版本號(hào)已經(jīng)獲取的鎖。
后者認(rèn)同前者的原則:
在肯定舊epoch 無(wú)法生成確定性取值時(shí),新的 epoch 會(huì)提交自己的valu
一旦 舊epoch形成確定性取值,新的 epoch肯定可以獲取到此取值,并且會(huì)認(rèn)同此取值,不會(huì)被破壞。
步驟
P1 請(qǐng)求Acceptor的 #1,Acceptor 這時(shí)并沒(méi)有其他線程獲取到鎖,所以把鎖交給 P1,并返回這時(shí) #1 的值為null
然后 P1 向 第一個(gè) Acceptor 提交 #1 的值,Acceptor 接受并返回 OK
這個(gè)時(shí)候,P2向Acceptor請(qǐng)求#1上的鎖,因?yàn)榘姹咎?hào)更大,所以直接搶占了 P1 的鎖。這時(shí) Acceptor 返回了 OK并且返回了 #1 的值
這時(shí) P1 P向 后面兩個(gè) Acceptor 提交 #1 的值,但是由于中間的那個(gè)Acceptor 版本號(hào)已經(jīng)更改為 2 了,所以拒絕P1。第三個(gè) Acceptor 接受了,并且返回了 OK
由于后者認(rèn)同前者的原則,這時(shí) P1 已經(jīng)形成確定性取值了 V1 了,這時(shí)新的 P2 會(huì)認(rèn)同此取值,而不是提交自己的取值。所以,P2會(huì)選擇最新的那個(gè)取值 也就是V1 進(jìn)行提交。這時(shí)Acceptor 返回 OK
6.ZAB 協(xié)議 ( Zookeeper Atomic? Broadcast) 原子廣播協(xié)議:保證了發(fā)給各副本的消息順序相同
定義:原子廣播協(xié)議 ZAB 是一致性協(xié)議,Zookeeper 把其作為數(shù)據(jù)一致性的算法。ZAB 是在 Paxos 算法基礎(chǔ)上進(jìn)行擴(kuò)展而來(lái)的。Zookeeper 使用單一主進(jìn)程 Leader用于處理客戶端所有事務(wù)請(qǐng)求,采用 ZAB 協(xié)議將服務(wù)器狀態(tài)以事務(wù)形式廣播到所有 Follower 上,由于事務(wù)間可能存在著依賴關(guān)系,ZAB協(xié)議保證 Leader 廣播的變更序列被順序的處理,一個(gè)狀態(tài)被處理那么它所依賴的狀態(tài)也已經(jīng)提前被處理
核心思想:保證任意時(shí)刻只有一個(gè)節(jié)點(diǎn)是Leader,所有更新事務(wù)由Leader發(fā)起去更新所有副本 Follower,更新時(shí)用的是 兩段提交協(xié)議,只要多數(shù)節(jié)點(diǎn) prepare 成功,就通知他們commit。各個(gè)follower 要按當(dāng)初 leader 讓他們 prepare 的順序來(lái) apply 事務(wù)
協(xié)議狀態(tài)
Looking:系統(tǒng)剛啟動(dòng)時(shí) 或者 Leader 崩潰后正處于選舉狀態(tài)
Following:Follower 節(jié)點(diǎn)所處的狀態(tài),Follower與 Leader處于數(shù)據(jù)同步狀態(tài)
Leading:Leader 所處狀態(tài),當(dāng)前集群中有一個(gè) Leader 為主進(jìn)程
ZooKeeper啟動(dòng)時(shí)所有節(jié)點(diǎn)初始狀態(tài)為L(zhǎng)ooking,這時(shí)集群會(huì)嘗試選舉出一個(gè)Leader節(jié)點(diǎn),選舉出的Leader節(jié)點(diǎn)切換為L(zhǎng)eading狀態(tài);當(dāng)節(jié)點(diǎn)發(fā)現(xiàn)集群中已經(jīng)選舉出Leader則該節(jié)點(diǎn)會(huì)切換到Following狀態(tài),然后和Leader節(jié)點(diǎn)保持同步;當(dāng)Follower節(jié)點(diǎn)與Leader失去聯(lián)系時(shí)Follower節(jié)點(diǎn)則會(huì)切換到Looking狀態(tài),開(kāi)始新一輪選舉;在ZooKeeper的整個(gè)生命周期中每個(gè)節(jié)點(diǎn)都會(huì)在Looking、Following、Leading狀態(tài)間不斷轉(zhuǎn)換。
選舉出Leader節(jié)點(diǎn)后 ZAB 進(jìn)入原子廣播階段,這時(shí)Leader為和自己同步每個(gè)節(jié)點(diǎn) Follower 創(chuàng)建一個(gè)操作序列,一個(gè)時(shí)期一個(gè) Follower 只能和一個(gè)Leader保持同步
階段
Election: 在 Looking狀態(tài)中選舉出 Leader節(jié)點(diǎn),Leader的LastZXID總是最新的(只有l(wèi)astZXID的節(jié)點(diǎn)才有資格成為L(zhǎng)eade,這種情況下選舉出來(lái)的Leader總有最新的事務(wù)日志)。在選舉的過(guò)程中會(huì)對(duì)每個(gè)Follower節(jié)點(diǎn)的ZXID進(jìn)行對(duì)比只有highestZXID的Follower才可能當(dāng)選Leader
每個(gè)Follower都向其他節(jié)點(diǎn)發(fā)送選自身為L(zhǎng)eader的Vote投票請(qǐng)求,等待回復(fù);
Follower接受到的Vote如果比自身的大(ZXID更新)時(shí)則投票,并更新自身的Vote,否則拒絕投票;
每個(gè)Follower中維護(hù)著一個(gè)投票記錄表,當(dāng)某個(gè)節(jié)點(diǎn)收到過(guò)半的投票時(shí),結(jié)束投票并把該Follower選為L(zhǎng)eader,投票結(jié)束;
Discovery:Follower 節(jié)點(diǎn)向準(zhǔn) Leader推送 FollwerInfo,該信息包含了上一周期的epoch,接受準(zhǔn) Leader 的 NEWLEADER 指令
Sync:將 Follower 與 Leader的數(shù)據(jù)進(jìn)行同步,由Leader發(fā)起同步指令,最終保持?jǐn)?shù)據(jù)的一致性
Broadcast:Leader廣播 Proposal 與 Commit,Follower 接受 Proposal 與 commit。因?yàn)橐粋€(gè)時(shí)刻只有一個(gè)Leader節(jié)點(diǎn),若是更新請(qǐng)求,只能由Leader節(jié)點(diǎn)執(zhí)行(若連到的是 Follower 節(jié)點(diǎn),則需轉(zhuǎn)發(fā)到Leader節(jié)點(diǎn)執(zhí)行;讀請(qǐng)求可以從Follower 上讀取,若是要最新的數(shù)據(jù),則還是需要在 Leader上讀取)
消息廣播使用了TCP協(xié)議進(jìn)行通訊所有保證了接受和發(fā)送事務(wù)的順序性。廣播消息時(shí)Leader節(jié)點(diǎn)為每個(gè)事務(wù)Proposal分配一個(gè)全局遞增的ZXID(事務(wù)ID),每個(gè)事務(wù)Proposal都按照Z(yǔ)XID順序來(lái)處理(Paxos 保證不了)
Leader節(jié)點(diǎn)為每一個(gè)Follower節(jié)點(diǎn)分配一個(gè)隊(duì)列按事務(wù)ZXID順序放入到隊(duì)列中,且根據(jù)隊(duì)列的規(guī)則FIFO來(lái)進(jìn)行事務(wù)的發(fā)送。
Recovery?:根據(jù)Leader的事務(wù)日志對(duì)Follower 節(jié)點(diǎn)數(shù)據(jù)進(jìn)行同步更新
同步策略:
Follower將所有事務(wù)都同步完成后Leader會(huì)把該節(jié)點(diǎn)添加到可用Follower列表中;
Follower接收Leader的NEWLEADER指令,如果該指令中epoch比當(dāng)前Follower的epoch小那么Follower轉(zhuǎn)到Election階段
SNAP?:如果Follower數(shù)據(jù)太老,Leader將發(fā)送快照SNAP指令給Follower同步數(shù)據(jù);
DIFF?:Leader發(fā)送從Follolwer.lastZXID到Leader.lastZXID議案的DIFF指令給Follower同步數(shù)據(jù);
TRUNC?:當(dāng)Follower.lastZXID比Leader.lastZXID大時(shí),Leader發(fā)送從Leader.lastZXID到Follower.lastZXID的TRUNC指令讓Follower丟棄該段數(shù)據(jù);(當(dāng)老Leader在Commit前掛掉,但是已提交到本地)
7. Raft 算法
Raft 算法也是一種少數(shù)服從多數(shù)的算法,在任何時(shí)候一個(gè)服務(wù)器可以扮演以下角色之一:
Leader:負(fù)責(zé) Client 交互 和 log 復(fù)制,同一時(shí)刻系統(tǒng)中最多存在一個(gè)
Follower:被動(dòng)響應(yīng)請(qǐng)求 RPC,從不主動(dòng)發(fā)起請(qǐng)求 RPC
Candidate : 由Follower 向Leader轉(zhuǎn)換的中間狀態(tài)
在選舉Leader的過(guò)程中,是有時(shí)間限制的,raft 將時(shí)間分為一個(gè)個(gè) Term,可以認(rèn)為是“邏輯時(shí)間”:
每個(gè) Term中至多存在1個(gè) Leader
某些 Term由于不止一個(gè)得到的票數(shù)一樣,就會(huì)選舉失敗,不存在Leader。則會(huì)出現(xiàn) Split Vote? ,再由候選者發(fā)出邀票
每個(gè) Server 本地維護(hù) currentTerm
選舉過(guò)程:
獲得超過(guò)半數(shù)的Server的投票,轉(zhuǎn)換為 Leader,廣播 HeatBeat
接收到 合法 Leader 的 AppendEnties RPC,轉(zhuǎn)換為Follower
選舉超時(shí),沒(méi)有 Server選舉成功,自增 currentTerm ,重新選舉
自增 CurrentTerm,由Follower 轉(zhuǎn)換為 Candidate,設(shè)置 votedFor 為自身,并行發(fā)起 RequestVote RPC,不斷重試,直至滿足下列條件之一為止:
當(dāng)Candidate 在等待投票結(jié)果的過(guò)程中,可能會(huì)接收到來(lái)自其他Leader的 AppendEntries RPC ,如果該 Leader 的 Term 不小于本地的 Current Term,則認(rèn)可該Leader身份的合法性,主動(dòng)降級(jí)為Follower,反之,則維持 candida 身份繼續(xù)等待投票結(jié)果
Candidate 既沒(méi)有選舉成功,也沒(méi)有收到其他 Leader 的 RPC (多個(gè)節(jié)點(diǎn)同時(shí)發(fā)起選舉,最終每個(gè) Candidate都將超時(shí)),為了減少?zèng)_突,采取隨機(jī)退讓策略,每個(gè) Candidate 重啟選舉定時(shí)器
日志更新問(wèn)題:
如果在日志復(fù)制過(guò)程中,發(fā)生了網(wǎng)絡(luò)分區(qū)或者網(wǎng)絡(luò)通信故障,使得Leader不能訪問(wèn)大多數(shù)Follwers了,那么Leader只能正常更新它能訪問(wèn)的那些Follower服務(wù)器,而大多數(shù)的服務(wù)器Follower因?yàn)闆](méi)有了Leader,他們重新選舉一個(gè)候選者作為L(zhǎng)eader,然后這個(gè)Leader作為代表于外界打交道,如果外界要求其添加新的日志,這個(gè)新的Leader就按上述步驟通知大多數(shù)Followers,如果這時(shí)網(wǎng)絡(luò)故障修復(fù)了,那么原先的Leader就變成Follower,在失聯(lián)階段這個(gè)老Leader的任何更新都不能算commit,都回滾,接受新的Leader的新的更新。
流程:
解決辦法:Client 賦予每個(gè) Command唯一標(biāo)識(shí),Leader在接收 command 之前首先檢查本地log
Client 發(fā)送command 命令給 Leader
Leader追加日志項(xiàng),等待 commit 更新本地狀態(tài)機(jī),最終響應(yīng) Client
若 Client超時(shí),則不斷重試,直到收到響應(yīng)為止(重發(fā) command,可能被執(zhí)行多次,在被執(zhí)行但是由于網(wǎng)絡(luò)通信問(wèn)題未收到響應(yīng))
9. paxos 算法與 raft 算法的差異
raft強(qiáng)調(diào)是唯一leader的協(xié)議,此leader至高無(wú)上
raft:新選舉出來(lái)的leader擁有全部提交的日志,而 paxos 需要額外的流程從其他節(jié)點(diǎn)獲取已經(jīng)被提交的日志,它允許日志有空洞
相同點(diǎn):得到大多數(shù)的贊成,這個(gè) entries 就會(huì)定下來(lái),最終所有節(jié)點(diǎn)都會(huì)贊成
NWR模型
N: N個(gè)備份
W:要寫入至少 w 份才認(rèn)為成功
R : 至少讀取 R 個(gè)備份
W+ R > N??? ——>??? R > N - W(未更新成功的) ,代表每次讀取,都至少讀取到一個(gè)最新的版本(更新成功的),從而不會(huì)讀到一份舊數(shù)據(jù)
問(wèn)題:并非強(qiáng)一致性,會(huì)出現(xiàn)一些節(jié)點(diǎn)上的數(shù)據(jù)并不是最新版本,但卻進(jìn)行了最新的操作
版本沖突問(wèn)題:矢量鐘 Vector Clock : 誰(shuí)更新的我,我的版本號(hào)是什么(對(duì)于同一個(gè)操作者的同一操作,版本號(hào)遞增)
參考資料:
http://www.tuicool.com/articles/IfQR3u3
http://blog.csdn.net/chen77716/article/details/7309915
http://www.infoq.com/cn/articles/distributed-system-transaction-processing/
http://www.jdon.com/artichect/raft.html
http://blog.csdn.net/cszhouwei/article/details/38374603
原文地址:http://blog.csdn.net/followmyinclinations/article/details/52870418
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的分布式事务与一致性算法Paxos amp; raft amp; zab的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: asp.net core mvc实现伪静
- 下一篇: Xamarin的坑 - 绑定(二) -