分布式理論
1. 說(shuō)說(shuō)CAP原則?
CAP原則又稱CAP定理,指的是在一個(gè)分布式系統(tǒng)中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區(qū)容錯(cuò)性)這3個(gè)基本需求,最多只能同時(shí)滿足其中的2個(gè)。
CAP原則
選項(xiàng) | 描述 |
---|---|
Consistency(一致性) | 指數(shù)據(jù)在多個(gè)副本之間能夠保持一致的特性(嚴(yán)格的一致性) |
Availability(可用性) | 指系統(tǒng)提供的服務(wù)必須一直處于可用的狀態(tài),每次請(qǐng)求都能獲取到非錯(cuò)的響應(yīng)(不保證獲取的數(shù)據(jù)為最新數(shù)據(jù)) |
Partition tolerance(分區(qū)容錯(cuò)性) | 分布式系統(tǒng)在遇到任何網(wǎng)絡(luò)分區(qū)故障的時(shí)候,仍然能夠?qū)ν馓峁M足一致性和可用性的服務(wù),除非整個(gè)網(wǎng)絡(luò)環(huán)境都發(fā)生了故障 |
2. 為什么CAP不可兼得呢?
首先對(duì)于分布式系統(tǒng),分區(qū)是必然存在的,所謂分區(qū)指的是分布式系統(tǒng)可能出現(xiàn)的字區(qū)域網(wǎng)絡(luò)不通,成為孤立區(qū)域的的情況。
分區(qū)
那么分區(qū)容錯(cuò)性(P)就必須要滿足,因?yàn)槿绻獱奚謪^(qū)容錯(cuò)性,就得把服務(wù)和資源放到一個(gè)機(jī)器,或者一個(gè)“同生共死”的集群,那就違背了分布式的初衷。那么滿足分區(qū)容錯(cuò)的基礎(chǔ)上,能不能同時(shí)滿足一致性和可用性?假如現(xiàn)在有兩個(gè)分區(qū)N1和N2,N1和N2分別有不同的分區(qū)存儲(chǔ)D1和D2,以及不同的服務(wù)S1和S2。
在滿足一致性 的時(shí)候,N1和N2的數(shù)據(jù)要求值一樣的,D1=D2。
在滿足可用性的時(shí)候,無(wú)論訪問(wèn)N1還是N2,都能獲取及時(shí)的響應(yīng)。
分區(qū)的服務(wù)
假如現(xiàn)在有這樣的場(chǎng)景:
用戶訪問(wèn)了N1,修改了D1的數(shù)據(jù)。
用戶再次訪問(wèn),請(qǐng)求落在了N2。此時(shí)D1和D2的數(shù)據(jù)不一致。
接下來(lái):
保證一致性:此時(shí)D1和D2數(shù)據(jù)不一致,要保證一致性就不能返回不一致的數(shù)據(jù),可用性無(wú)法保證。
保證可用性:立即響應(yīng),可用性得到了保證,但是此時(shí)響應(yīng)的數(shù)據(jù)和D1不一致,一致性無(wú)法保證。
所以,可以看出,分區(qū)容錯(cuò)的前提下,一致性和可用性是矛盾的。
3. CAP對(duì)應(yīng)的模型和應(yīng)用?
CA without P理論上放棄P(分區(qū)容錯(cuò)性),則C(強(qiáng)一致性)和A(可用性)是可以保證的。實(shí)際上分區(qū)是不可避免的,嚴(yán)格上CA指的是允許分區(qū)后各子系統(tǒng)依然保持CA。CA模型的常見(jiàn)應(yīng)用:
集群數(shù)據(jù)庫(kù)
xFS文件系統(tǒng)
CP without A放棄A(可用),相當(dāng)于每個(gè)請(qǐng)求都需要在Server之間強(qiáng)一致,而P(分區(qū))會(huì)導(dǎo)致同步時(shí)間無(wú)限延長(zhǎng),如此CP也是可以保證的。很多傳統(tǒng)的數(shù)據(jù)庫(kù)分布式事務(wù)都屬于這種模式。CP模型的常見(jiàn)應(yīng)用:
分布式數(shù)據(jù)庫(kù)
分布式鎖
AP wihtout C要高可用并允許分區(qū),則需放棄一致性。一旦分區(qū)發(fā)生,節(jié)點(diǎn)之間可能會(huì)失去聯(lián)系,為了高可用,每個(gè)節(jié)點(diǎn)只能用本地?cái)?shù)據(jù)提供服務(wù),而這樣會(huì)導(dǎo)致全局?jǐn)?shù)據(jù)的不一致性?,F(xiàn)在眾多的NoSQL都屬于此類。AP模型常見(jiàn)應(yīng)用:
Web緩存
DNS
舉個(gè)大家更熟悉的例子,像我們熟悉的注冊(cè)中心ZooKeeper、Eureka、Nacos中:
ZooKeeper 保證的是 CP
Eureka 保證的則是 AP
Nacos 不僅支持 CP 也支持 AP
4. BASE理論了解嗎?
BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理論逐步演化而來(lái)的,核心思想是即便不能達(dá)到強(qiáng)一致性(Strong consistency),也可以根據(jù)應(yīng)用特點(diǎn)采用適當(dāng)?shù)姆绞絹?lái)達(dá)到最終一致性(Eventual consistency)的效果。
BASE的主要含義:
Basically Available(基本可用)
什么是基本可用呢?假設(shè)系統(tǒng)出現(xiàn)了不可預(yù)知的故障,但還是能用,只是相比較正常的系統(tǒng)而言,可能會(huì)有響應(yīng)時(shí)間上的損失,或者功能上的降級(jí)。
Soft State(軟狀態(tài))
什么是硬狀態(tài)呢?要求多個(gè)節(jié)點(diǎn)的數(shù)據(jù)副本都是一致的,這是一種“硬狀態(tài)”。軟狀態(tài)也稱為弱狀態(tài),相比較硬狀態(tài)而言,允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該狀態(tài)不影響系統(tǒng)的整體可用性,即允許系統(tǒng)在多個(gè)不同節(jié)點(diǎn)的數(shù)據(jù)副本存在數(shù)據(jù)延時(shí)。
Eventually Consistent(最終一致性)
上面說(shuō)了軟狀態(tài),但是不應(yīng)該一直都是軟狀態(tài)。在一定時(shí)間后,應(yīng)該到達(dá)一個(gè)最終的狀態(tài),保證所有副本保持?jǐn)?shù)據(jù)一致性,從而達(dá)到數(shù)據(jù)的最終一致性。這個(gè)時(shí)間取決于網(wǎng)絡(luò)延時(shí)、系統(tǒng)負(fù)載、數(shù)據(jù)復(fù)制方案設(shè)計(jì)等等因素。
分布式鎖
單體時(shí)代,可以直接用本地鎖來(lái)實(shí)現(xiàn)對(duì)競(jìng)爭(zhēng)資源的加鎖,分布式環(huán)境下就要用到分布式鎖了。
5. 有哪些分布式鎖的實(shí)現(xiàn)方案呢?
常見(jiàn)的分布式鎖實(shí)現(xiàn)方案有三種:MySQL分布式鎖、ZooKepper分布式鎖、Redis分布式鎖。
分布式鎖
5.1 MySQL分布式鎖如何實(shí)現(xiàn)呢?
用數(shù)據(jù)庫(kù)實(shí)現(xiàn)分布式鎖比較簡(jiǎn)單,就是創(chuàng)建一張鎖表,數(shù)據(jù)庫(kù)對(duì)字段作唯一性約束。加鎖的時(shí)候,在鎖表中增加一條記錄即可;釋放鎖的時(shí)候刪除記錄就行。如果有并發(fā)請(qǐng)求同時(shí)提交到數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)會(huì)保證只有一個(gè)請(qǐng)求能夠得到鎖。這種屬于數(shù)據(jù)庫(kù) IO 操作,效率不高,而且頻繁操作會(huì)增大數(shù)據(jù)庫(kù)的開(kāi)銷,因此這種方式在高并發(fā)、高性能的場(chǎng)景中用的不多。
5.2 ZooKeeper如何實(shí)現(xiàn)分布式鎖?
ZooKeeper也是常見(jiàn)分布式鎖實(shí)現(xiàn)方法。ZooKeeper的數(shù)據(jù)節(jié)點(diǎn)和文件目錄類似,例如有一個(gè)lock節(jié)點(diǎn),在此節(jié)點(diǎn)下建立子節(jié)點(diǎn)是可以保證先后順序的,即便是兩個(gè)進(jìn)程同時(shí)申請(qǐng)新建節(jié)點(diǎn),也會(huì)按照先后順序建立兩個(gè)節(jié)點(diǎn)。
ZooKeeper如何實(shí)現(xiàn)分布式鎖
所以我們可以用此特性實(shí)現(xiàn)分布式鎖。以某個(gè)資源為目錄,然后這個(gè)目錄下面的節(jié)點(diǎn)就是我們需要獲取鎖的客戶端,每個(gè)服務(wù)在目錄下創(chuàng)建節(jié)點(diǎn),如果它的節(jié)點(diǎn),序號(hào)在目錄下最小,那么就獲取到鎖,否則等待。釋放鎖,就是刪除服務(wù)創(chuàng)建的節(jié)點(diǎn)。ZK實(shí)際上是一個(gè)比較重的分布式組件,實(shí)際上應(yīng)用沒(méi)那么多了,所以用ZK實(shí)現(xiàn)分布式鎖,其實(shí)相對(duì)也比較少。
5.3 Redis怎么實(shí)現(xiàn)分布式鎖?
Redis實(shí)現(xiàn)分布式鎖,是當(dāng)前應(yīng)用最廣泛的分布式鎖實(shí)現(xiàn)方式。Redis執(zhí)行命令是單線程的,Redis實(shí)現(xiàn)分布式鎖就是利用這個(gè)特性。實(shí)現(xiàn)分布式鎖最簡(jiǎn)單的一個(gè)命令:setNx(set if not exist),如果不存在則更新:
setNx?resourceName?value??
加鎖了之后如果機(jī)器宕機(jī),那我這個(gè)鎖就無(wú)法釋放,所以需要加入過(guò)期時(shí)間,而且過(guò)期時(shí)間需要和setNx同一個(gè)原子操作,在Redis2.8之前需要用lua腳本,但是redis2.8之后redis支持nx和ex操作是同一原子操作。
Redission
當(dāng)然,一般生產(chǎn)中都是使用Redission客戶端,非常良好地封裝了分布式鎖的api,而且支持RedLock。
分布式事務(wù)
6.什么是分布式事務(wù)?
分布式事務(wù)是相對(duì)本地事務(wù)而言的,對(duì)于本地事務(wù),利用數(shù)據(jù)庫(kù)本身的事務(wù)機(jī)制,就可以保證事務(wù)的ACID特性。
ACID
而在分布式環(huán)境下,會(huì)涉及到多個(gè)數(shù)據(jù)庫(kù)。
多數(shù)據(jù)庫(kù)
分布式事務(wù)其實(shí)就是將對(duì)同一庫(kù)事務(wù)的概念擴(kuò)大到了對(duì)多個(gè)庫(kù)的事務(wù)。目的是為了保證分布式系統(tǒng)中的數(shù)據(jù)一致性。分布式事務(wù)處理的關(guān)鍵是:
需要記錄事務(wù)在任何節(jié)點(diǎn)所做的所有動(dòng)作;
事務(wù)進(jìn)行的所有操作要么全部提交,要么全部回滾。
7.分布式事務(wù)有哪些常見(jiàn)的實(shí)現(xiàn)方案?
分布式常見(jiàn)的實(shí)現(xiàn)方案有 2PC、3PC、TCC、本地消息表、MQ消息事務(wù)、最大努力通知、SAGA事務(wù) 等等。
7.1 說(shuō)說(shuō)2PC兩階段提交?
說(shuō)到2PC,就不得先說(shuō)分布式事務(wù)中的 XA 協(xié)議。在這個(gè)協(xié)議里,有三個(gè)角色:
AP(Application):應(yīng)用系統(tǒng)(服務(wù))
TM(Transaction Manager):事務(wù)管理器(全局事務(wù)管理)
RM(Resource Manager):資源管理器(數(shù)據(jù)庫(kù))
XA協(xié)議
XA協(xié)議采用兩階段提交方式來(lái)管理分布式事務(wù)。XA接口提供資源管理器與事務(wù)管理器之間進(jìn)行通信的標(biāo)準(zhǔn)接口。兩階段提交的思路可以概括為:參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情況決定各參與者是否要提交操作還是回滾操作。
2PC
準(zhǔn)備階段:事務(wù)管理器要求每個(gè)涉及到事務(wù)的數(shù)據(jù)庫(kù)預(yù)提交(precommit)此操作,并反映是否可以提交
提交階段:事務(wù)協(xié)調(diào)器要求每個(gè)數(shù)據(jù)庫(kù)提交數(shù)據(jù),或者回滾數(shù)據(jù)。
優(yōu)點(diǎn):盡量保證了數(shù)據(jù)的強(qiáng)一致,實(shí)現(xiàn)成本較低,在各大主流數(shù)據(jù)庫(kù)都有自己實(shí)現(xiàn),對(duì)于MySQL是從5.5開(kāi)始支持。缺點(diǎn):
單點(diǎn)問(wèn)題:事務(wù)管理器在整個(gè)流程中扮演的角色很關(guān)鍵,如果其宕機(jī),比如在第一階段已經(jīng)完成,在第二階段正準(zhǔn)備提交的時(shí)候事務(wù)管理器宕機(jī),資源管理器就會(huì)一直阻塞,導(dǎo)致數(shù)據(jù)庫(kù)無(wú)法使用。
同步阻塞:在準(zhǔn)備就緒之后,資源管理器中的資源一直處于阻塞,直到提交完成,釋放資源。
數(shù)據(jù)不一致:兩階段提交協(xié)議雖然為分布式數(shù)據(jù)強(qiáng)一致性所設(shè)計(jì),但仍然存在數(shù)據(jù)不一致性的可能,比如在第二階段中,假設(shè)協(xié)調(diào)者發(fā)出了事務(wù)commit的通知,但是因?yàn)榫W(wǎng)絡(luò)問(wèn)題該通知僅被一部分參與者所收到并執(zhí)行了commit操作,其余的參與者則因?yàn)闆](méi)有收到通知一直處于阻塞狀態(tài),這時(shí)候就產(chǎn)生了數(shù)據(jù)的不一致性。
7.2 3PC(三階段提交)了解嗎?
三階段提交(3PC)是二階段提交(2PC)的一種改進(jìn)版本 ,為解決兩階段提交協(xié)議的單點(diǎn)故障和同步阻塞問(wèn)題。三階段提交有這么三個(gè)階段:CanCommit,PreCommit,DoCommit三個(gè)階段
3PC
CanCommit:準(zhǔn)備階段。協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)。
PreCommit:預(yù)提交階段。協(xié)調(diào)者根據(jù)參與者在準(zhǔn)備階段的響應(yīng)判斷是否執(zhí)行事務(wù)還是中斷事務(wù),參與者執(zhí)行完操作之后返回ACK響應(yīng),同時(shí)開(kāi)始等待最終指令。
DoCommit:提交階段。協(xié)調(diào)者根據(jù)參與者在準(zhǔn)備階段的響應(yīng)判斷是否執(zhí)行事務(wù)還是中斷事務(wù):
如果所有參與者都返回正確的ACK響應(yīng),則提交事務(wù)
如果參與者有一個(gè)或多個(gè)參與者收到錯(cuò)誤的ACK響應(yīng)或者超時(shí),則中斷事務(wù)
如果參與者無(wú)法及時(shí)接收到來(lái)自協(xié)調(diào)者的提交或者中斷事務(wù)請(qǐng)求時(shí),在等待超時(shí)之后,會(huì)繼續(xù)進(jìn)行事務(wù)提交
可以看出,三階段提交解決的只是兩階段提交中單體故障和同步阻塞的問(wèn)題,因?yàn)榧尤肓顺瑫r(shí)機(jī)制,這里的超時(shí)的機(jī)制作用于 預(yù)提交階段 和 提交階段。如果等待 預(yù)提交請(qǐng)求 超時(shí),參與者直接回到準(zhǔn)備階段之前。如果等到提交請(qǐng)求超時(shí),那參與者就會(huì)提交事務(wù)了。無(wú)論是2PC還是3PC都不能保證分布式系統(tǒng)中的數(shù)據(jù)100%一致。
7.3 TCC了解嗎?
TCC(Try Confirm Cancel) ,是兩階段提交的一個(gè)變種,針對(duì)每個(gè)操作,都需要有一個(gè)其對(duì)應(yīng)的確認(rèn)和取消操作,當(dāng)操作成功時(shí)調(diào)用確認(rèn)操作,當(dāng)操作失敗時(shí)調(diào)用取消操作,類似于二階段提交,只不過(guò)是這里的提交和回滾是針對(duì)業(yè)務(wù)上的,所以基于TCC實(shí)現(xiàn)的分布式事務(wù)也可以看做是對(duì)業(yè)務(wù)的一種補(bǔ)償機(jī)制。
TCC下單減庫(kù)存
Try:嘗試待執(zhí)行的業(yè)務(wù)。訂單系統(tǒng)將當(dāng)前訂單狀態(tài)設(shè)置為支付中,庫(kù)存系統(tǒng)校驗(yàn)當(dāng)前剩余庫(kù)存數(shù)量是否大于1,然后將可用庫(kù)存數(shù)量設(shè)置為庫(kù)存剩余數(shù)量-1,。
Confirm:確認(rèn)執(zhí)行業(yè)務(wù),如果Try階段執(zhí)行成功,接著執(zhí)行Confirm 階段,將訂單狀態(tài)修改為支付成功,庫(kù)存剩余數(shù)量修改為可用庫(kù)存數(shù)量。
Cancel:取消待執(zhí)行的業(yè)務(wù),如果Try階段執(zhí)行失敗,執(zhí)行Cancel 階段,將訂單狀態(tài)修改為支付失敗,可用庫(kù)存數(shù)量修改為庫(kù)存剩余數(shù)量。
TCC 是業(yè)務(wù)層面的分布式事務(wù),保證最終一致性,不會(huì)一直持有資源的鎖。
優(yōu)點(diǎn): 把數(shù)據(jù)庫(kù)層的二階段提交交給應(yīng)用層來(lái)實(shí)現(xiàn),規(guī)避了數(shù)據(jù)庫(kù)的 2PC 性能低下問(wèn)題
缺點(diǎn):TCC 的 Try、Confirm 和 Cancel 操作功能需業(yè)務(wù)提供,開(kāi)發(fā)成本高。TCC 對(duì)業(yè)務(wù)的侵入較大和業(yè)務(wù)緊耦合,需要根據(jù)特定的場(chǎng)景和業(yè)務(wù)邏輯來(lái)設(shè)計(jì)相應(yīng)的操作
7.4 本地消息表了解嗎?
本地消息表的核心思想是將分布式事務(wù)拆分成本地事務(wù)進(jìn)行處理。例如,可以在訂單庫(kù)新增一個(gè)消息表,將新增訂單和新增消息放到一個(gè)事務(wù)里完成,然后通過(guò)輪詢的方式去查詢消息表,將消息推送到MQ,庫(kù)存服務(wù)去消費(fèi)MQ。
本地消息表
執(zhí)行流程:
訂單服務(wù),添加一條訂單和一條消息,在一個(gè)事務(wù)里提交
訂單服務(wù),使用定時(shí)任務(wù)輪詢查詢狀態(tài)為未同步的消息表,發(fā)送到MQ,如果發(fā)送失敗,就重試發(fā)送
庫(kù)存服務(wù),接收MQ消息,修改庫(kù)存表,需要保證冪等操作
如果修改成功,調(diào)用rpc接口修改訂單系統(tǒng)消息表的狀態(tài)為已完成或者直接刪除這條消息
如果修改失敗,可以不做處理,等待重試
訂單服務(wù)中的消息有可能由于業(yè)務(wù)問(wèn)題會(huì)一直重復(fù)發(fā)送,所以為了避免這種情況可以記錄一下發(fā)送次數(shù),當(dāng)達(dá)到次數(shù)限制之后報(bào)警,人工接入處理;庫(kù)存服務(wù)需要保證冪等,避免同一條消息被多次消費(fèi)造成數(shù)據(jù)不一致。本地消息表這種方案實(shí)現(xiàn)了最終一致性,需要在業(yè)務(wù)系統(tǒng)里增加消息表,業(yè)務(wù)邏輯中多一次插入的DB操作,所以性能會(huì)有損耗,而且最終一致性的間隔主要有定時(shí)任務(wù)的間隔時(shí)間決定
7.5 MQ消息事務(wù)了解嗎?
消息事務(wù)的原理是將兩個(gè)事務(wù)通過(guò)消息中間件進(jìn)行異步解耦。訂單服務(wù)執(zhí)行自己的本地事務(wù),并發(fā)送MQ消息,庫(kù)存服務(wù)接收消息,執(zhí)行自己的本地事務(wù),乍一看,好像跟本地消息表的實(shí)現(xiàn)方案類似,只是省去 了對(duì)本地消息表的操作和輪詢發(fā)送MQ的操作,但實(shí)際上兩種方案的實(shí)現(xiàn)是不一樣的。消息事務(wù)一定要保證業(yè)務(wù)操作與消息發(fā)送的一致性,如果業(yè)務(wù)操作成功,這條消息也一定投遞成功。
MQ消息事務(wù)
執(zhí)行流程:
發(fā)送prepare消息到消息中間件
發(fā)送成功后,執(zhí)行本地事務(wù)
如果事務(wù)執(zhí)行成功,則commit,消息中間件將消息下發(fā)至消費(fèi)端
如果事務(wù)執(zhí)行失敗,則回滾,消息中間件將這條prepare消息刪除
消費(fèi)端接收到消息進(jìn)行消費(fèi),如果消費(fèi)失敗,則不斷重試
消息事務(wù)依賴于消息中間件的事務(wù)消息,例如我們熟悉的RocketMQ就支持事務(wù)消息(半消息),也就是只有收到發(fā)送方確定才會(huì)正常投遞的消息。這種方案也是實(shí)現(xiàn)了最終一致性,對(duì)比本地消息表實(shí)現(xiàn)方案,不需要再建消息表,對(duì)性能的損耗和業(yè)務(wù)的入侵更小。
7.6 最大努力通知了解嗎?
最大努力通知相比實(shí)現(xiàn)會(huì)簡(jiǎn)單一些,適用于一些對(duì)最終一致性實(shí)時(shí)性要求沒(méi)那么高的業(yè)務(wù),比如支付通知,短信通知。以支付通知為例,業(yè)務(wù)系統(tǒng)調(diào)用支付平臺(tái)進(jìn)行支付,支付平臺(tái)進(jìn)行支付,進(jìn)行操作支付之后支付平臺(tái)會(huì)去同步通知業(yè)務(wù)系統(tǒng)支付操作是否成功,如果不成功,會(huì)一直異步重試,但是會(huì)有一個(gè)最大通知次數(shù),如果超過(guò)這個(gè)次數(shù)后還是通知失敗,就不再通知,業(yè)務(wù)系統(tǒng)自行調(diào)用支付平臺(tái)提供一個(gè)查詢接口,供業(yè)務(wù)系統(tǒng)進(jìn)行查詢支付操作是否成功。
最大努力通知
執(zhí)行流程:
業(yè)務(wù)系統(tǒng)調(diào)用支付平臺(tái)支付接口, 并在本地進(jìn)行記錄,支付狀態(tài)為支付中
支付平臺(tái)進(jìn)行支付操作之后,無(wú)論成功還是失敗,同步給業(yè)務(wù)系統(tǒng)一個(gè)結(jié)果通知
如果通知一直失敗則根據(jù)重試規(guī)則異步進(jìn)行重試,達(dá)到最大通知次數(shù)后,不再通知
支付平臺(tái)提供查詢訂單支付操作結(jié)果接口
業(yè)務(wù)系統(tǒng)根據(jù)一定業(yè)務(wù)規(guī)則去支付平臺(tái)查詢支付結(jié)果
8.你們用什么?能說(shuō)一下Seata嗎?
我們用比較常用的是Seata——自己去實(shí)現(xiàn)分布式事務(wù)調(diào)度還是比較麻煩的。Seata 的設(shè)計(jì)目標(biāo)是對(duì)業(yè)務(wù)無(wú)侵入,因此它是從業(yè)務(wù)無(wú)侵入的兩階段提交(全局事務(wù))著手,在傳統(tǒng)的兩階段上進(jìn)行改進(jìn),他把一個(gè)分布式事務(wù)理解成一個(gè)包含了若干分支事務(wù)的全局事務(wù)。而全局事務(wù)的職責(zé)是協(xié)調(diào)它管理的分支事務(wù)達(dá)成一致性,要么一起成功提交,要么一起失敗回滾。也就是一榮俱榮一損俱損~
全局事務(wù)和分支事務(wù)
Seata 中存在這么幾種重要角色:
TC(Transaction Coordinator):事務(wù)協(xié)調(diào)者。管理全局的分支事務(wù)的狀態(tài),用于全局性事務(wù)的提交和回滾。
TM(Transaction Manager):事務(wù)管理者。用于開(kāi)啟、提交或回滾事務(wù)。
RM(Resource Manager):資源管理器。用于分支事務(wù)上的資源管理,向 TC 注冊(cè)分支事務(wù),上報(bào)分支事務(wù)的狀態(tài),接收 TC 的命令來(lái)提交或者回滾分支事務(wù)。
Seata工作流程
S'eata整體執(zhí)行流程:
服務(wù)A中的 TM 向 TC 申請(qǐng)開(kāi)啟一個(gè)全局事務(wù),TC 就會(huì)創(chuàng)建一個(gè)全局事務(wù)并返回一個(gè)唯一的 XID
服務(wù)A中的 RM 向 TC 注冊(cè)分支事務(wù),然后將這個(gè)分支事務(wù)納入 XID 對(duì)應(yīng)的全局事務(wù)管轄中
服務(wù)A開(kāi)始執(zhí)行分支事務(wù)
服務(wù)A開(kāi)始遠(yuǎn)程調(diào)用B服務(wù),此時(shí) XID 會(huì)根據(jù)調(diào)用鏈傳播
服務(wù)B中的 RM 也向 TC 注冊(cè)分支事務(wù),然后將這個(gè)分支事務(wù)納入 XID 對(duì)應(yīng)的全局事務(wù)管轄中
服務(wù)B開(kāi)始執(zhí)行分支事務(wù)
全局事務(wù)調(diào)用處理結(jié)束后,TM 會(huì)根據(jù)有誤異常情況,向 TC 發(fā)起全局事務(wù)的提交或回滾
TC 協(xié)調(diào)其管轄之下的所有分支事務(wù),決定是提交還是回滾
分布式一致性算法
9.分布式算法paxos了解么 ?
Paxos 有點(diǎn)類似前面說(shuō)的 2PC,3PC,但比這兩種算法更加完善。在很多多大廠都得到了工程實(shí)踐,比如阿里的 OceanBase 的 分布式數(shù)據(jù)庫(kù), Google 的 chubby 分布式鎖 。
Paxos算法是什么?
Paxos 算法是 基于消息傳遞 且具有 高效容錯(cuò)特性 的一致性算法,目前公認(rèn)的解決 分布式一致性問(wèn)題 最有效的算法之一。
Paxos算法的工作流程?
角色
在Paxos中有這么幾個(gè)角色:
Proposer(提議者) : 提議者提出提案,用于投票表決。
Accecptor(接受者) : 對(duì)提案進(jìn)行投票,并接受達(dá)成共識(shí)的提案。
Learner(學(xué)習(xí)者) : 被告知投票的結(jié)果,接受達(dá)成共識(shí)的提案。
在實(shí)際中,一個(gè)節(jié)點(diǎn)可以同時(shí)充當(dāng)不同角色。
Paxos的三種角色
提議者提出提案,提案=編號(hào)+value,可以表示為[M,V],每個(gè)提案都有唯一編號(hào),而且編號(hào)的大小是趨勢(shì)遞增的。
算法流程
Paxos算法包含兩個(gè)階段,第一階段**Prepare(準(zhǔn)備)、第二階段Accept(接受)**。
Paxos算法流程
Prepare(準(zhǔn)備)階段
提議者提議一個(gè)新的提案 P[Mn,?],然后向接受者的某個(gè)超過(guò)半數(shù)的子集成員發(fā)送編號(hào)為Mn的準(zhǔn)備請(qǐng)求
如果一個(gè)接受者收到一個(gè)編號(hào)為Mn的準(zhǔn)備請(qǐng)求,并且編號(hào)Mn大于它已經(jīng)響應(yīng)的所有準(zhǔn)備請(qǐng)求的編號(hào),那么它就會(huì)將它已經(jīng)批準(zhǔn)過(guò)的最大編號(hào)的提案作為響應(yīng)反饋給提議者,同時(shí)該接受者會(huì)承諾不會(huì)再批準(zhǔn)任何編號(hào)小于Mn的提案。
總結(jié)一下,接受者在收到提案后,會(huì)給與提議者兩個(gè)承諾與一個(gè)應(yīng)答:
兩個(gè)承諾:
承諾不會(huì)再接受提案號(hào)小于或等于 Mn 的 Prepare 請(qǐng)求
承諾不會(huì)再接受提案號(hào)小于Mn 的 Accept 請(qǐng)求
一個(gè)應(yīng)答:
不違背以前作出的承諾的前提下,回復(fù)已經(jīng)通過(guò)的提案中提案號(hào)最大的那個(gè)提案所設(shè)定的值和提案號(hào)Mmax,如果這個(gè)值從來(lái)沒(méi)有被任何提案設(shè)定過(guò),則返回空值。如果不滿足已經(jīng)做出的承諾,即收到的提案號(hào)并不是決策節(jié)點(diǎn)收到過(guò)的最大的,那允許直接對(duì)此 Prepare 請(qǐng)求不予理會(huì)。
Accept(接受)階段
如果提議者收到來(lái)自半數(shù)以上的接受者對(duì)于它發(fā)出的編號(hào)為Mn的準(zhǔn)備請(qǐng)求的響應(yīng),那么它就會(huì)發(fā)送一個(gè)針對(duì)[Mn,Vn]的接受請(qǐng)求給接受者,注意Vn的值就是收到的響應(yīng)中編號(hào)最大的提案的值,如果響應(yīng)中不包含任何提案,那么它可以隨意選定一個(gè)值。
如果接受者收到這個(gè)針對(duì)[Mn,Vn]提案的接受請(qǐng)求,只要該接受者尚未對(duì)編號(hào)大于Mn的準(zhǔn)備請(qǐng)求做出響應(yīng),它就可以通過(guò)這個(gè)提案。
當(dāng)提議者收到了多數(shù)接受者的接受應(yīng)答后,協(xié)商結(jié)束,共識(shí)決議形成,將形成的決議發(fā)送給所有學(xué)習(xí)節(jié)點(diǎn)進(jìn)行學(xué)習(xí)。所以Paxos算法的整體詳細(xì)流程如下:
Paxos詳細(xì)流程
算法的流程模擬,可以查看參考[13]。
Paxos算法有什么缺點(diǎn)嗎?怎么優(yōu)化?
前面描述的可以稱之為Basic Paxos 算法,在單提議者的前提下是沒(méi)有問(wèn)題的,但是假如有多個(gè)提議者互不相讓,那么就可能導(dǎo)致整個(gè)提議的過(guò)程進(jìn)入了死循環(huán)。Lamport 提出了 Multi Paxos 的算法思想。Multi Paxos算法思想,簡(jiǎn)單說(shuō)就是在多個(gè)提議者的情況下,選出一個(gè)Leader(領(lǐng)導(dǎo)者),由領(lǐng)導(dǎo)者作為唯一的提議者,這樣就可以解決提議者沖突的問(wèn)題。
10.說(shuō)說(shuō)Raft算法?
Raft算法是什么?
Raft 也是一個(gè) 一致性算法,和 Paxos 目標(biāo)相同。但它還有另一個(gè)名字 - 易于理解的一致性算法。Paxos 和 Raft 都是為了實(shí)現(xiàn) 一致性 產(chǎn)生的。這個(gè)過(guò)程如同選舉一樣,參選者 需要說(shuō)服 大多數(shù)選民 (Server) 投票給他,一旦選定后就跟隨其操作。Paxos 和 Raft 的區(qū)別在于選舉的 具體過(guò)程 不同。
Raft算法的工作流程?
Raft算法的角色
Raft 協(xié)議將 Server 進(jìn)程分為三種角色:
Leader(領(lǐng)導(dǎo)者)
Follower(跟隨者)
Candidate(候選人)
就像一個(gè)民主社會(huì),領(lǐng)導(dǎo)者由跟隨者投票選出。剛開(kāi)始沒(méi)有 領(lǐng)導(dǎo)者,所有集群中的 參與者 都是 跟隨者。那么首先開(kāi)啟一輪大選。在大選期間 所有跟隨者 都能參與競(jìng)選,這時(shí)所有跟隨者的角色就變成了 候選人,民主投票選出領(lǐng)袖后就開(kāi)始了這屆領(lǐng)袖的任期,然后選舉結(jié)束,所有除 領(lǐng)導(dǎo)者 的 候選人 又變回 跟隨者 服從領(lǐng)導(dǎo)者領(lǐng)導(dǎo)。這里提到一個(gè)概念 「任期」,用術(shù)語(yǔ) Term 表達(dá)。三類角色的變遷圖如下:
Raft三種角色變遷圖
Leader選舉過(guò)程
Raft 使用心跳(heartbeat)觸發(fā)Leader選舉。當(dāng)Server啟動(dòng)時(shí),初始化為Follower。Leader向所有Followers周期性發(fā)送heartbeat。如果Follower在選舉超時(shí)時(shí)間內(nèi)沒(méi)有收到Leader的heartbeat,就會(huì)等待一段隨機(jī)的時(shí)間后發(fā)起一次Leader選舉。Follower將其當(dāng)前term加一然后轉(zhuǎn)換為Candidate。它首先給自己投票并且給集群中的其他服務(wù)器發(fā)送 RequestVote RPC 。結(jié)果有以下三種情況:
贏得了多數(shù)(超過(guò)1/2)的選票,成功選舉為L(zhǎng)eader;
收到了Leader的消息,表示有其它服務(wù)器已經(jīng)搶先當(dāng)選了Leader;
沒(méi)有Server贏得多數(shù)的選票,Leader選舉失敗,等待選舉時(shí)間超時(shí)(Election Timeout)后發(fā)起下一次選舉。
Leader選舉
選出 Leader 后,Leader 通過(guò) 定期 向所有 Follower 發(fā)送 心跳信息 維持其統(tǒng)治。若 Follower 一段時(shí)間未收到 Leader 的 心跳,則認(rèn)為 Leader 可能已經(jīng)掛了,然后再次發(fā)起 選舉 過(guò)程。
分布式設(shè)計(jì)
11.說(shuō)說(shuō)什么是冪等性?
什么是冪等性?
冪等性是一個(gè)數(shù)學(xué)概念,用在接口上:用在接口上就可以理解為:同一個(gè)接口,多次發(fā)出同一個(gè)請(qǐng)求,請(qǐng)求的結(jié)果是一致的。簡(jiǎn)單說(shuō),就是多次調(diào)用如一次。
什么是冪等性問(wèn)題?
在系統(tǒng)的運(yùn)行中,可能會(huì)出現(xiàn)這樣的問(wèn)題:
用戶在填寫某些form表單時(shí),保存按鈕不小心快速點(diǎn)了兩次,表中竟然產(chǎn)生了兩條重復(fù)的數(shù)據(jù),只是id不一樣。
開(kāi)發(fā)人員在項(xiàng)目中為了解決接口超時(shí)問(wèn)題,通常會(huì)引入了重試機(jī)制。第一次請(qǐng)求接口超時(shí)了,請(qǐng)求方?jīng)]能及時(shí)獲取返回結(jié)果(此時(shí)有可能已經(jīng)成功了),于是會(huì)對(duì)該請(qǐng)求重試幾次,這樣也會(huì)產(chǎn)生重復(fù)的數(shù)據(jù)。
mq消費(fèi)者在讀取消息時(shí),有時(shí)候會(huì)讀取到重復(fù)消息,也會(huì)產(chǎn)生重復(fù)的數(shù)據(jù)。
這些都是常見(jiàn)的冪等性問(wèn)題。在分布式系統(tǒng)里,只要下游服務(wù)有寫(保存、更新)的操作,都有可能會(huì)產(chǎn)生冪等性問(wèn)題。PS:冪等和防重有些不同,防重強(qiáng)調(diào)的防止數(shù)據(jù)重復(fù),冪等強(qiáng)調(diào)的是多次調(diào)用如一次,防重包含冪等。
怎么保證接口冪等性?
接口冪等性
insert前先select在保存數(shù)據(jù)的接口中,在insert前,先根據(jù)requestId等字段先select一下數(shù)據(jù)。如果該數(shù)據(jù)已存在,則直接返回,如果不存在,才執(zhí)行 ?insert操作。
加唯一索引加唯一索引是個(gè)非常簡(jiǎn)單但很有效的辦法,如果重復(fù)插入數(shù)據(jù)的話,就會(huì)拋出異常,為了保證冪等性,一般需要捕獲這個(gè)異常。如果是java程序需要捕獲:DuplicateKeyException異常,如果使用了spring框架還需要捕獲:MySQLIntegrityConstraintViolationException異常。
加悲觀鎖更新邏輯,比如更新用戶賬戶余額,可以加悲觀鎖,把對(duì)應(yīng)用戶的哪一行數(shù)據(jù)鎖住。同一時(shí)刻只允許一個(gè)請(qǐng)求獲得鎖,其他請(qǐng)求則等待。
?
?
????select?*?from?user?id=123?for?update;??
這種方式有一個(gè)缺點(diǎn),獲取不到鎖的請(qǐng)求一般只能報(bào)失敗,比較難保證接口返回相同值。
?
?
加樂(lè)觀鎖更新邏輯,也可以用樂(lè)觀鎖,性能更好??梢栽诒碇性黾右粋€(gè)timestamp或者version字段,例如version:在更新前,先查詢一下數(shù)據(jù),將version也作為更新的條件,同時(shí)也更新version:
?
?
update?user?set?amount=amount+100,version=version+1?where?id=123?and?version=1;??
更新成功后,version增加,重復(fù)更新請(qǐng)求進(jìn)來(lái)就無(wú)法更新了。
?
?
建防重表有時(shí)候表中并非所有的場(chǎng)景都不允許產(chǎn)生重復(fù)的數(shù)據(jù),只有某些特定場(chǎng)景才不允許。這時(shí)候,就可以使用防重表的方式。例如消息消費(fèi)中,創(chuàng)建防重表,存儲(chǔ)消息的唯一ID,消費(fèi)時(shí)先去查詢是否已經(jīng)消費(fèi),已經(jīng)消費(fèi)直接返回成功。
狀態(tài)機(jī)有些業(yè)務(wù)表是有狀態(tài)的,比如訂單表中有:1-下單、2-已支付、3-完成、4-撤銷等狀態(tài),可以通過(guò)限制狀態(tài)的流動(dòng)來(lái)完成冪等。
分布式鎖直接在數(shù)據(jù)庫(kù)上加鎖的做法性能不夠友好,可以使用分布式鎖的方式,目前最流行的分布式鎖實(shí)現(xiàn)是通過(guò)Redis,具體實(shí)現(xiàn)一般都是使用Redission框架。
token機(jī)制請(qǐng)求接口之前,需要先獲取一個(gè)唯一的token,再帶著這個(gè)token去完成業(yè)務(wù)操作,服務(wù)端根據(jù)這個(gè)token是否存在,來(lái)判斷是否是重復(fù)的請(qǐng)求。
分布式限流
12.你了解哪些限流算法?
計(jì)數(shù)器
計(jì)數(shù)器比較簡(jiǎn)單粗暴,比如我們要限制1s能夠通過(guò)的請(qǐng)求數(shù),實(shí)現(xiàn)的思路就是從第一個(gè)請(qǐng)求進(jìn)來(lái)開(kāi)始計(jì)時(shí),在接下來(lái)的1s內(nèi),每個(gè)請(qǐng)求進(jìn)來(lái)請(qǐng)求數(shù)就+1,超過(guò)最大請(qǐng)求數(shù)的請(qǐng)求會(huì)被拒絕,等到1s結(jié)束后計(jì)數(shù)清零,重新開(kāi)始計(jì)數(shù)。這種方式有個(gè)很大的弊端:比如前10ms已經(jīng)通過(guò)了最大的請(qǐng)求數(shù),那么后面的990ms的請(qǐng)求只能拒絕,這種現(xiàn)象叫做“突刺現(xiàn)象”。
漏桶算法
就是桶底出水的速度恒定,進(jìn)水的速度可能快慢不一,但是當(dāng)進(jìn)水量大于出水量的時(shí)候,水會(huì)被裝在桶里,不會(huì)直接被丟棄;但是桶也是有容量限制的,當(dāng)桶裝滿水后溢出的部分還是會(huì)被丟棄的。算法實(shí)現(xiàn):可以準(zhǔn)備一個(gè)隊(duì)列來(lái)保存暫時(shí)處理不了的請(qǐng)求,然后通過(guò)一個(gè)線程池定期從隊(duì)列中獲取請(qǐng)求來(lái)執(zhí)行。
漏桶算法
令牌桶算法
令牌桶就是生產(chǎn)訪問(wèn)令牌的一個(gè)地方,生產(chǎn)的速度恒定,用戶訪問(wèn)的時(shí)候當(dāng)桶中有令牌時(shí)就可以訪問(wèn),否則將觸發(fā)限流。實(shí)現(xiàn)方案:Guava RateLimiter限流Guava RateLimiter是一個(gè)谷歌提供的限流,其基于令牌桶算法,比較適用于單實(shí)例的系統(tǒng)。
令牌桶算法
分布式面試題就整理到這里了,主要是偏理論的一些問(wèn)題,分布式其實(shí)是個(gè)很大的類型
編輯:黃飛
?
評(píng)論