SpringCloud(四) 微服务架构-事务一致性
分布式事務(wù)指事務(wù)的操作位于不同的節(jié)點(diǎn)上,需要保證事務(wù)的 AICD 特性。目前比較常用的分布式事務(wù)解決方案包括強(qiáng)一致性的兩階段提交協(xié)議、三階段提交協(xié)議以及最終一致性的可靠事件模式、補(bǔ)償模式、阿里的TCC模式。
事務(wù)是指由一組操作組成的一個(gè)工作單元,這個(gè)工作單元具有原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)。 原子性:執(zhí)行單元中的操作要么全部執(zhí)行成功,要么全部失敗。如果有一部分成功一部分失敗那么成功的操作要全部回滾到執(zhí)行前的狀態(tài)。 一致性:執(zhí)行一次事務(wù)會(huì)使用數(shù)據(jù)從一個(gè)正確的狀態(tài)轉(zhuǎn)換到另一個(gè)正確的狀態(tài),執(zhí)行前后數(shù)據(jù)都是完整的。
隔離性:在該事務(wù)執(zhí)行的過程中,任何數(shù)據(jù)的改變只存在于該事務(wù)之中,對(duì)外界沒有影響,事務(wù)與事務(wù)之間是完全的隔離的。只有事務(wù)提交后其它事務(wù)才可以查詢到最新的數(shù)據(jù)。 持久性:事務(wù)完成后對(duì)數(shù)據(jù)的改變會(huì)永久性的存儲(chǔ)起來,即使發(fā)生斷電宕機(jī)數(shù)據(jù)依然在。
強(qiáng)一致性
兩階段提交協(xié)議
在分布式系統(tǒng)中,為了解決多個(gè)節(jié)點(diǎn)之間的協(xié)調(diào)問題,就需要引入一個(gè)協(xié)調(diào)者負(fù)責(zé)控制所有節(jié)點(diǎn)的操作結(jié)果,要么全部成功,要么全部失敗。其中,XA協(xié)議是一個(gè)分布式事務(wù)協(xié)議,它有兩個(gè)角色:事務(wù)管理者和資源管理者。我們可用把事務(wù)管理者理解為協(xié)調(diào)者,資源管理者理解為參與者。XA協(xié)議通過二階段提交協(xié)議保證強(qiáng)一致性:
第一階段準(zhǔn)備:事務(wù)管理者向資源管理者發(fā)起準(zhǔn)備指令,詢問資源管理者預(yù)提交是否成功;資源管理者執(zhí)行操作,并不提交,最后給出自己的響應(yīng)結(jié)果
第二階段提交:如果全部資源管理者都回復(fù)預(yù)提交成功,事務(wù)管理者則發(fā)起正式提交命令;如果其中一個(gè)資源管理者回復(fù)預(yù)提交失敗,事務(wù)管理者則發(fā)起全部回滾命令
二階段提交協(xié)議的缺點(diǎn)
同步阻塞問題:執(zhí)行過程中,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的。當(dāng)參與者占有公共資源時(shí),其他第三方節(jié)點(diǎn)訪問公共資源不得不處于阻塞狀態(tài)。
單點(diǎn)故障:由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障。參與者會(huì)一直阻塞下去。尤其在第二階段,協(xié)調(diào)者發(fā)生故障,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作。(如果是協(xié)調(diào)者掛掉,可以重新選舉一個(gè)協(xié)調(diào)者,但是無法解決因?yàn)閰f(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問題)
數(shù)據(jù)不一致:在二階段提交的階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求之后,發(fā)生了局部網(wǎng)絡(luò)異?;蛘咴诎l(fā)送commit請(qǐng)求過程中協(xié)調(diào)者發(fā)生了故障,這回導(dǎo)致只有一部分參與者接受到了commit請(qǐng)求。而在這部分參與者接到commit請(qǐng)求之后就會(huì)執(zhí)行commit操作。但是其他部分未接到commit請(qǐng)求的機(jī)器則無法執(zhí)行事務(wù)提交。于是整個(gè)分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象。
三階段提交協(xié)議
三階段提交協(xié)議與二階段的不同之處在于引入了超時(shí)機(jī)制來解決同步阻塞問題,此外加入預(yù)備階段,盡可能最早發(fā)現(xiàn)無法執(zhí)行的資源管理者并終止事務(wù)。
最終一致性
TCC模式
TCC模式將一個(gè)任務(wù)拆分為3個(gè)操作:Try、Confirm和Cancel。在TCC模式中,主業(yè)務(wù)服務(wù)負(fù)責(zé)發(fā)起流程,而從業(yè)務(wù)服務(wù)提供TCC模式的Try、Confirm和Cancel三個(gè)操作,還有一個(gè)事務(wù)管理器的角色負(fù)責(zé)控制事務(wù)的一致性。事實(shí)上,TCC模式也是一種二階段提交。
用戶接入TCC,最重要的是考慮如何將自己的業(yè)務(wù)模型拆成兩階段來實(shí)現(xiàn)。
例如:賬戶業(yè)務(wù)服務(wù),將業(yè)務(wù)劃分為資源(余額)檢查與預(yù)留階段 與 執(zhí)行扣款或回滾階段。
Try 方法作為一階段準(zhǔn)備方法(做資源的檢查和預(yù)留)
在扣錢場景下,Try 要做的事情是就是檢查賬戶余額是否充足,預(yù)留轉(zhuǎn)賬資金,預(yù)留的方式就是凍結(jié) A 賬戶的 轉(zhuǎn)賬資金。
Try 方法執(zhí)行之后,賬號(hào) A 余額雖然還是 100,但是**其中 10 元已經(jīng)被凍結(jié)了,不能被其他事務(wù)使用**。
二階段 Confirm 方法(執(zhí)行真正的扣錢操作)
Confirm 會(huì)使用 Try 階段凍結(jié)的資金,執(zhí)行賬號(hào)扣款。Confirm 方法執(zhí)行之后,賬號(hào) A 在一階段中凍結(jié)的 10 元已經(jīng)被扣除,賬號(hào) A 余額變成 70 元 。
如果二階段是回滾的話,就需要在 Cancel 方法內(nèi)釋放一階段 Try 凍結(jié)的 10 元,使賬號(hào) A 的回到初始狀態(tài),100 元全部可用
需要注意的是,第二階段 confirm 或 cancel 操作本身也是滿足最終一致性的過程,在調(diào)用 confirm 或 cancel 的時(shí)候也可能因?yàn)槟撤N原因(比如網(wǎng)絡(luò))導(dǎo)致調(diào)用失敗,所以需要活動(dòng)管理支持重試的能力,同時(shí)這也就要求 confirm 和 cancel 操作具有冪等性(所謂冪等,就是任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同)。如果業(yè)務(wù)服務(wù)向 TCC 服務(wù)框架提交confirm/cancel 失敗,不會(huì)導(dǎo)致不一致,因?yàn)榉?wù)最后都會(huì)超時(shí)而取消。TCC的實(shí)現(xiàn)框架有很多成熟的開源項(xiàng)目,比如tcc-transaction。它通過@Compensable切面進(jìn)行攔截,可以透明化對(duì)參與者confirm/cancel方法的調(diào)用,從而實(shí)現(xiàn)TCC模式
補(bǔ)償模式
除了重試機(jī)制,還可以在每次更新時(shí)進(jìn)行修復(fù)。定時(shí)校對(duì)也是一種重要的解決手段。業(yè)內(nèi)比較常用的有單機(jī)場景下的Quartz以及分布式場景下的XXL-JOB等。
可靠事件模式
可靠事件模式是指通過引入可靠的消息隊(duì)列,只要保證當(dāng)前的可靠事件投遞并且消息隊(duì)列確保事件傳遞至少一次,那么訂閱這個(gè)事件的消費(fèi)者保證事件能夠在自己的業(yè)務(wù)內(nèi)被消費(fèi)即可。但是在網(wǎng)絡(luò)通信過程中,上下游可能因?yàn)楦鞣N原因而導(dǎo)致消息丟失。因此,需要通過“正反向消息機(jī)制”確保消息隊(duì)列實(shí)現(xiàn)可靠的事件傳遞,并且使用補(bǔ)償機(jī)制盡可能在一定時(shí)間內(nèi)將未完成的消息重新投遞。
一般做法,是主業(yè)務(wù)服務(wù)將要發(fā)送的消息持久化到本地?cái)?shù)據(jù)庫中,設(shè)置標(biāo)志狀態(tài)為“待發(fā)送”;然后把消息發(fā)送給消息隊(duì)列,消息隊(duì)列收到消息后,也把消息持久化到其存儲(chǔ)服務(wù)中,但并不是立即向從業(yè)務(wù)服務(wù)(生產(chǎn)者)投遞消息,而是先向主業(yè)務(wù)服務(wù)(生產(chǎn)者)返回消息隊(duì)列的響應(yīng)結(jié)果,然后主業(yè)務(wù)服務(wù)判斷響應(yīng)結(jié)果執(zhí)行之后的業(yè)務(wù)處理。如果響應(yīng)失敗,則放棄之后的業(yè)務(wù)處理,設(shè)置本地的持久化消息標(biāo)志狀態(tài)為“結(jié)束”狀態(tài)。否則,執(zhí)行后續(xù)的業(yè)務(wù)處理,設(shè)置本地的持久化消息標(biāo)志狀態(tài)為“已發(fā)送"狀態(tài)。
Apache RockerMQ
Apache RockerMQ是阿里開源的分布式消息中間件,4.3版本正式支持分布式事務(wù)消息。RockerMQ事務(wù)消息中間件解決了生產(chǎn)者端的消息發(fā)送與本地事務(wù)執(zhí)行的原子性問題。 換句話說,本地事務(wù)執(zhí)行不成功,則不會(huì)進(jìn)行MQ消息推送。
MQ消息、DB操作一致性方案:
1)發(fā)送消息到MQ服務(wù)器,此時(shí)消息狀態(tài)為SEND_OK。此消息為consumer不可見。
2)執(zhí)行DB操作;DB執(zhí)行成功Commit DB操作,DB執(zhí)行失敗Rollback DB操作。
3)如果DB執(zhí)行成功,回復(fù)MQ服務(wù)器,將狀態(tài)為COMMIT_MESSAGE;如果DB執(zhí)行失敗,回復(fù)MQ服務(wù)器,將狀態(tài)改為ROLLBACK_MESSAGE。注意此過程有可能失敗。
4)MQ內(nèi)部提供一個(gè)名為“事務(wù)狀態(tài)服務(wù)”的服務(wù),此服務(wù)會(huì)檢查事務(wù)消息的狀態(tài),如果發(fā)現(xiàn)消息未COMMIT,則通過Producer啟動(dòng)時(shí)注冊的TransactionCheckListener來回調(diào)業(yè)務(wù)系統(tǒng),業(yè)務(wù)系統(tǒng)在checkLocalTransactionState方法中檢查DB事務(wù)狀態(tài),如果成功,則回復(fù)COMMIT_MESSAGE,否則回復(fù)ROLLBACK_MESSAGE
總結(jié)
以上是生活随笔為你收集整理的SpringCloud(四) 微服务架构-事务一致性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运用runtime与AOP实现oc中的k
- 下一篇: 列出每一个部门中年纪最大的员工姓名,部门