1 背景
在講述分布式事務(wù)的概念之前,我們先來回顧下事務(wù)相關(guān)的一些概念。
1.1 事務(wù)的基本概念
就是一個程序執(zhí)行單元,里面的操作要么全部執(zhí)行成功,要么全部執(zhí)行失敗,不允許只成功一半另外一半執(zhí)行失敗的事情發(fā)生。例如一段事務(wù)代碼做了兩次數(shù)據(jù)庫更新操作,那么這兩次數(shù)據(jù)庫操作要么全部執(zhí)行成功,要么全部回滾。
1.2 事務(wù)的基本特性
我們知道事務(wù)有4個非常重要的特性,即我們常說的(ACID)。
- Atomicity(原子性):一個事務(wù)(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被恢復(fù)(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。
- Consistency(一致性):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)規(guī)則,這包含資料的精確度、串聯(lián)性以及后續(xù)數(shù)據(jù)庫可以自發(fā)性地完成預(yù)定的工作。
- Isolation(隔離性):數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)。
- Durability(持久性):事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失
2 分布式事務(wù)
其實(shí)分布式事務(wù)從實(shí)質(zhì)上看與數(shù)據(jù)庫事務(wù)的概念是一致的,既然是事務(wù)也就需要滿足事務(wù)的基本特性(ACID),只是分布式事務(wù)相對于本地事務(wù)而言其表現(xiàn)形式有很大的不同。
本地事務(wù)的時代,如果需要同時操作數(shù)據(jù)庫的多條記錄,而這些操作可以放到一個事務(wù)中,那么我們可以通過數(shù)據(jù)庫提供的事務(wù)機(jī)制就可以實(shí)現(xiàn)。
而隨著微服務(wù)架構(gòu)的推進(jìn),原本一個本地邏輯執(zhí)行單元,被拆分到了多個獨(dú)立的微服務(wù)中,這些微服務(wù)又分別操作了不同的數(shù)據(jù)庫和表。
比如下個指派個體的運(yùn)輸任務(wù),下運(yùn)輸任務(wù)的同時要生成需求、計(jì)劃、任務(wù),還要去調(diào)用詢價(jià)服務(wù),投保服務(wù),那么,一旦產(chǎn)生任何一個服務(wù)異常,都會產(chǎn)生事務(wù)性的問題。雖然對于我們現(xiàn)有邏輯來說,可以由運(yùn)營作廢,但未來自動化之后呢?
分布式事務(wù)是為了解決微服務(wù)架構(gòu)(形式都是分布式系統(tǒng))中不同節(jié)點(diǎn)之間的數(shù)據(jù)一致性問題。這個一致性問題本質(zhì)上解決的也是傳統(tǒng)事務(wù)需要解決的問題,即一個請求在多個微服務(wù)調(diào)用鏈中,所有服務(wù)的數(shù)據(jù)處理要么全部成功,要么全部回滾。當(dāng)然分布式事務(wù)問題的形式可能與傳統(tǒng)事務(wù)會有比較大的差異,但是問題本質(zhì)是一致的,都是要求解決數(shù)據(jù)的一致性問題。
而分布式事務(wù)的實(shí)現(xiàn)方式有很多種,最具有代表性的是由Oracle Tuxedo系統(tǒng)提出的XA分布式事務(wù)協(xié)議。XA協(xié)議包括兩階段提交(2PC)和三階段提交(3PC)兩種實(shí)現(xiàn),接下來我們分別來介紹下這兩種實(shí)現(xiàn)方式的原理。
3 兩階段提交(2PC)
兩階段提交又稱2PC(two-phase commit protocol),2PC是一個非常經(jīng)典的強(qiáng)一致、中心化的原子提交協(xié)議。這里所說的中心化是指協(xié)議中有兩個角色:一個是分布式事務(wù)協(xié)調(diào)者(coordinator)和N個參與者(participant)。
3.1 2PC運(yùn)行原理
兩階段提交,顧名思義就是要進(jìn)行兩個階段的提交:第一階段,準(zhǔn)備階段(投票階段);第二階段,提交階段(執(zhí)行階段)。
3.1.1 準(zhǔn)備階段(Prepare phase)
- 分布式事務(wù)的發(fā)起方,向分布式事務(wù)協(xié)調(diào)者(Coordinator,也可以叫事務(wù)管理TransactionManager)發(fā)送請求,
- Coordinator分別向參與者(Participant)A、參與者(Participant)B分別發(fā)送事務(wù)預(yù)處理請求,稱之為Prepare,有些資料也叫”Vote Request”。
- 此時這些參與者節(jié)點(diǎn)一般來說就會打開本地?cái)?shù)據(jù)庫事務(wù),然后開始執(zhí)行數(shù)據(jù)庫本地事務(wù),每個數(shù)據(jù)庫參與者在本地執(zhí)行事務(wù)并寫本地的Undo/Redo日志(Undo日志是記錄修改前的數(shù)據(jù),用于數(shù)據(jù)庫回滾,Redo日志是記錄修改后的數(shù)據(jù),用于提交事務(wù)后寫入數(shù)據(jù)文件),但在執(zhí)行完成后并不會立馬提交數(shù)據(jù)庫本地事務(wù),而是先向Coordinator進(jìn)行“Vote Commit”的反饋,告知處理結(jié)果。
- 如果所有的參與者都向協(xié)調(diào)者做了“Vote Commit”的反饋的話,那么流程進(jìn)入第二個階段。
3.1.2 提交階段(commit phase)
1)如果所有參與者均反饋的是成功,協(xié)調(diào)者就會向所有參與者發(fā)送“全局提交確認(rèn)通知(global_commit)”,參與者Participant就會完成自身本地?cái)?shù)據(jù)庫事務(wù)的提交,并將提交結(jié)果回復(fù)“ack”消息給協(xié)調(diào)者Coordinator,然后協(xié)調(diào)者Coordinator就會向調(diào)用方返回分布式事務(wù)處理完成的結(jié)果。如果有任何一個參與者返回失敗,則回滾事務(wù)。
2)如果參與者向協(xié)調(diào)者反饋“Vote_Abort”消息,即返回了失敗的消息。此時分布式事務(wù)協(xié)調(diào)者Coordinator就會向所有的參與者Participant發(fā)起事務(wù)回滾的消息(“global_rollback”),此時各個參與者就會回滾本地事務(wù),釋放資源,并且向協(xié)調(diào)者發(fā)送“ack”確認(rèn)消息,協(xié)調(diào)者就會向調(diào)用方返回分布式事務(wù)處理失敗的結(jié)果。
以上就是兩階段提交的基本過程了,那么按照這個兩階段提交協(xié)議,分布式系統(tǒng)的數(shù)據(jù)一致性問題就能解決么?
3.2 2PC存在的問題
其實(shí),2PC只是通過增加了事務(wù)協(xié)調(diào)者(Coordinator)的角色來通過2個階段的處理流程來解決分布式系統(tǒng)中一個事務(wù)需要跨多個服務(wù)的數(shù)據(jù)一致性問題。
以下幾點(diǎn)是XA-兩階段提交協(xié)議中會遇到的一些問題:
- 性能問題:2PC中的所有的參與者節(jié)點(diǎn)都為事務(wù)阻塞型,當(dāng)某一個參與者節(jié)點(diǎn)出現(xiàn)通信超時,其余參與者都會被動阻塞占用資源不能釋放。
- 協(xié)調(diào)者單點(diǎn)故障問題:由于嚴(yán)重的依賴協(xié)調(diào)者,一旦協(xié)調(diào)者發(fā)生故障,而此時參與者還都處于鎖定資源的狀態(tài),無法完成事務(wù)commit操作。雖然協(xié)調(diào)者出現(xiàn)故障后,會重新選舉一個協(xié)調(diào)者,可無法解決因前一個協(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問題。
- 網(wǎng)絡(luò)閃斷導(dǎo)致腦裂:第二階段中協(xié)調(diào)者向參與者發(fā)送commit命令之后,一旦此時發(fā)生網(wǎng)絡(luò)抖動,導(dǎo)致一部分參與者接收到了commit請求并執(zhí)行,可其他未接到commit請求的參與者無法執(zhí)行事務(wù)提交。進(jìn)而導(dǎo)致整個分布式系統(tǒng)出現(xiàn)了數(shù)據(jù)不一致。
4 三階段提交(3PC)
三階段提交又稱3PC,在2PC的基礎(chǔ)上增加了CanCommit階段,并引入了超時機(jī)制。一旦事務(wù)參與者遲遲沒有收到協(xié)調(diào)者的Commit請求,就會自動進(jìn)行本地commit,這樣相對有效地解決了協(xié)調(diào)者單點(diǎn)故障的問題。
4.1 3PC運(yùn)行原理
4.1.1 CanCommit階段
- 協(xié)調(diào)者向參與者發(fā)出CanCommit ,進(jìn)行事務(wù)詢問操作,所有參與者都反饋yes后,才能進(jìn)入下一個階段。(這一個階段時不鎖表,不像2pc 第一個階段就開始鎖表,3pc的階段一是為了先排除個別參與者不具備提交事務(wù)能力的前提下,而避免鎖表。)簡單來說就是檢查下自身狀態(tài)的健康性。
- 有任何一個參與者反饋的結(jié)果是No,整個分布式事務(wù)就會中斷,協(xié)調(diào)者就會向所有的參與者發(fā)送“abort”請求。
4.1.2 PreCommit階段
- 在階段一中,如果所有的參與者都返回Yes的話,那么就會進(jìn)入PreCommit階段進(jìn)行事務(wù)預(yù)提交。此時分布式事務(wù)協(xié)調(diào)者會向所有的參與者發(fā)送PreCommit請求,參與者收到后開始執(zhí)行事務(wù)操作,并將Undo和Redo信息記錄到事務(wù)日志中。參與者執(zhí)行完事務(wù)操作后(此時屬于未提交事務(wù)的狀態(tài)),就會向協(xié)調(diào)者反饋“Ack”表示已經(jīng)準(zhǔn)備好提交,并等待協(xié)調(diào)者的下一步指令。
- 有任何一個參與者反饋的結(jié)果是No,或協(xié)調(diào)者在等待參與者節(jié)點(diǎn)反饋的過程中超時(2PC中只有協(xié)調(diào)者可以超時,參與者沒有超時機(jī)制)。整個分布式事務(wù)就會中斷,協(xié)調(diào)者就會向所有的參與者發(fā)送“abort”請求。
4.1.3 DoCommit階段
- 在階段二中如果所有的參與者都可以進(jìn)行PreCommit提交,那么協(xié)調(diào)者就會從“預(yù)提交狀態(tài)”->“提交狀態(tài)”。然后向所有的參與者發(fā)送”doCommit”請求,參與者在收到提交請求后,執(zhí)行事務(wù)提交操作,并向協(xié)調(diào)者反饋“Ack”消息,協(xié)調(diào)者收到所有參與者的Ack消息后完成事務(wù)。
- 同樣,如果有一個參與者節(jié)點(diǎn)未完成PreCommit的反饋或者反饋超時,那么協(xié)調(diào)者都會向所有的參與者節(jié)點(diǎn)發(fā)送abort請求,從而中斷事務(wù)。
相比較2PC而言,3PC對于協(xié)調(diào)者(Coordinator)和參與者(Participant)都設(shè)置了超時時間,解決了參與者在長時間無法與協(xié)調(diào)者節(jié)點(diǎn)通訊(協(xié)調(diào)者掛掉了)的情況下,無法釋放資源的問題,因?yàn)閰⑴c者自身擁有超時機(jī)制會在超時后,自動進(jìn)行本地commit從而進(jìn)行釋放資源。而這種機(jī)制也側(cè)面降低了整個事務(wù)的阻塞時間和范圍。
另外,通過CanCommit、PreCommit、DoCommit三個階段的設(shè)計(jì),相較于2PC而言,多設(shè)置了一個緩沖階段保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的。
3PC的缺點(diǎn):
3PC在去除阻塞的同時也引入了新的問題,那就是參與者接收到precommit消息后,如果出現(xiàn)網(wǎng)絡(luò)分區(qū),此時協(xié)調(diào)者所在的節(jié)點(diǎn)和參與者無法進(jìn)行正常的網(wǎng)絡(luò)通信,在這種情況下,該參與者依然會進(jìn)行事務(wù)的提交,這必然出現(xiàn)數(shù)據(jù)的不一致性。
5 補(bǔ)償事務(wù)(TCC)
TCC與2PC、3PC一樣,只是分布式事務(wù)的一種實(shí)現(xiàn)方案。
5.1 TCC原理:
TCC(Try-Confirm-Cancel)又稱補(bǔ)償事務(wù)。其核心思想是:”針對每個操作都要注冊一個與其對應(yīng)的確認(rèn)和補(bǔ)償(撤銷操作)”。它分為三個操作:
- Try階段:主要是對業(yè)務(wù)系統(tǒng)做檢測及資源預(yù)留,比如說凍結(jié)庫存。
- Confirm階段:確認(rèn)執(zhí)行業(yè)務(wù)操作。
- Cancel階段:取消執(zhí)行業(yè)務(wù)操作。
TCC事務(wù)的處理流程與2PC兩階段提交類似,不過2PC通常都是在跨庫的DB層面,而TCC本質(zhì)上就是一個應(yīng)用層面的2PC,需要通過業(yè)務(wù)邏輯來實(shí)現(xiàn)。這種分布式事務(wù)的實(shí)現(xiàn)方式的優(yōu)勢在于,可以讓應(yīng)用自己定義數(shù)據(jù)庫操作的粒度,使得降低鎖沖突、提高吞吐量成為可能。
而不足之處則在于對應(yīng)用的侵入性非常強(qiáng),業(yè)務(wù)邏輯的每個分支都需要實(shí)現(xiàn)try、confirm、cancel三個操作。此外,其實(shí)現(xiàn)難度也比較大,需要按照網(wǎng)絡(luò)狀態(tài)、系統(tǒng)故障等不同的失敗原因?qū)崿F(xiàn)不同的回滾策略。為了滿足一致性的要求,confirm和cancel接口還必須實(shí)現(xiàn)冪等。
TCC的具體原理圖如下:
5.2 注意事項(xiàng):
1.業(yè)務(wù)操作分兩階段完成:
接入TCC前,業(yè)務(wù)操作只需要一步就能完成,但是在接入TCC之后,需要考慮如何將其分成2階段完成,把資源的檢查和預(yù)留放在一階段的Try操作中進(jìn)行,把真正的業(yè)務(wù)操作的執(zhí)行放在二階段的Confirm操作中進(jìn)行;
TCC服務(wù)要保證第一階段Try操作成功之后,二階段Confirm操作一定能成功;
2.允許空回滾;
事務(wù)協(xié)調(diào)器在調(diào)用TCC服務(wù)的一階段Try操作時,可能會出現(xiàn)因?yàn)閬G包而導(dǎo)致的網(wǎng)絡(luò)超時,此時事務(wù)協(xié)調(diào)器會觸發(fā)二階段回滾,調(diào)用TCC服務(wù)的Cancel操作;
TCC服務(wù)在未收到Try請求的情況下收到Cancel請求,這種場景被稱為空回滾;TCC服務(wù)在實(shí)現(xiàn)時應(yīng)當(dāng)允許空回滾的執(zhí)行;
3.防懸掛控制;
事務(wù)協(xié)調(diào)器在調(diào)用TCC服務(wù)的一階段Try操作時,可能會出現(xiàn)因網(wǎng)絡(luò)擁堵而導(dǎo)致的超時,此時事務(wù)協(xié)調(diào)器會觸發(fā)二階段回滾,調(diào)用TCC服務(wù)的Cancel操作;在此之后,擁堵在網(wǎng)絡(luò)上的一階段Try數(shù)據(jù)包被TCC服務(wù)收到,出現(xiàn)了二階段Cancel請求比一階段Try請求先執(zhí)行的情況;
用戶在實(shí)現(xiàn)TCC服務(wù)時,應(yīng)當(dāng)允許空回滾,但是要拒絕執(zhí)行空回滾之后到來的一階段Try請求;
4.冪等控制:
無論是網(wǎng)絡(luò)數(shù)據(jù)包重傳,還是異常事務(wù)的補(bǔ)償執(zhí)行,都會導(dǎo)致TCC服務(wù)的Try、Confirm或者Cancel操作被重復(fù)執(zhí)行;用戶在實(shí)現(xiàn)TCC服務(wù)時,需要考慮冪等控制,即Try、Confirm、Cancel 執(zhí)行次和執(zhí)行多次的業(yè)務(wù)結(jié)果是一樣的;
5.業(yè)務(wù)數(shù)據(jù)可見性控制;
TCC服務(wù)的一階段Try操作會做資源的預(yù)留,在二階段操作執(zhí)行之前,如果其他事務(wù)需要讀取被預(yù)留的資源數(shù)據(jù),那么處于中間狀態(tài)的業(yè)務(wù)數(shù)據(jù)該如何向用戶展示,需要業(yè)務(wù)在實(shí)現(xiàn)時考慮清楚;通常的設(shè)計(jì)原則是“寧可不展示、少展示,也不多展示、錯展示”;
6.業(yè)務(wù)數(shù)據(jù)并發(fā)訪問控制;
TCC服務(wù)的一階段Try操作預(yù)留資源之后,在二階段操作執(zhí)行之前,預(yù)留的資源都不會被釋放;如果此時其他分布式事務(wù)修改這些業(yè)務(wù)資源,會出現(xiàn)分布式事務(wù)的并發(fā)問題;
用戶在實(shí)現(xiàn)TCC服務(wù)時,需要考慮業(yè)務(wù)數(shù)據(jù)的并發(fā)控制,盡量將邏輯鎖粒度降到最低,以最大限度的提高分布式事務(wù)的并發(fā)性;
6 Hmily
Hmily (How much I love you)
高性能分布式事務(wù)tcc開源框架。基于java語言來開發(fā)(JDK1.8),支持dubbo,springcloud,motan等rpc框架進(jìn)行分布式事務(wù)。
框架特性
- 支持嵌套事務(wù)(Nested transaction support).
- 采用disruptor框架進(jìn)行事務(wù)日志的異步讀寫,與RPC框架的性能毫無差別。
- 支持SpringBoot-starter 項(xiàng)目啟動,使用簡單。
- RPC框架支持 : dubbo,motan,springcloud。
- 本地事務(wù)存儲支持 : redis,mongodb,zookeeper,file,mysql。
- 事務(wù)日志序列化支持 :java,hessian,kryo,protostuff。
- 采用Aspect AOP 切面思想與Spring無縫集成,天然支持集群。
- 內(nèi)置經(jīng)典的分布式事務(wù)場景demo工程,并有swagger-ui可視化界面可以快速體驗(yàn)。
6.1 Hmily原理及流程圖
原理圖:
流程圖:
7 參考文獻(xiàn)
- https://dromara.org/website/zh-cn/docs/hmily/index.html
- https://houbb.github.io/2018/10/30/hmily
- https://developer.aliyun.com/article/609854
- https://blog.csdn.net/bjweimengshu/article/details/86698036
- https://blog.csdn.net/u014296316/article/details/90185589
作者:京東物流 宋樂文章來源:http://www.zghlxwxcb.cn/news/detail-710793.html
來源:京東云開發(fā)者社區(qū) 自猿其說Tech 轉(zhuǎn)載請注明來源文章來源地址http://www.zghlxwxcb.cn/news/detail-710793.html
到了這里,關(guān)于淺談分布式事務(wù)及解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!