截取轉(zhuǎn)載自https://draveness.me/distributed-transaction-principle
事務(wù)實(shí)現(xiàn)原理
-
事務(wù)日志
為了實(shí)現(xiàn)確保事務(wù)能在執(zhí)行的任意過(guò)程中回滾(原子性)并且提交的事務(wù)會(huì)永久保存在數(shù)據(jù)庫(kù)中瓜富,我們會(huì)使用事務(wù)日志來(lái)存儲(chǔ)事務(wù)執(zhí)行過(guò)程中的數(shù)據(jù)庫(kù)的變動(dòng),每一條事務(wù)日志中都包含事務(wù)的 ID纽什、當(dāng)前被修改的元素厘托、變動(dòng)前以及變動(dòng)后的值
- 并發(fā)控制
數(shù)據(jù)庫(kù)作為最關(guān)鍵的后端服務(wù),很難想象只能串行執(zhí)行每一個(gè)數(shù)據(jù)庫(kù)操作帶來(lái)的性能影響稿湿,然而在并發(fā)執(zhí)行 SQL 的過(guò)程中就可能無(wú)法保證數(shù)據(jù)庫(kù)對(duì)于隔離性的要求,歸根結(jié)底這就是一致性押赊、隔離性與性能之間的權(quán)衡饺藤。
為了避免并發(fā)帶來(lái)的一致性問(wèn)題、滿足數(shù)據(jù)庫(kù)對(duì)于隔離性要求流礁,數(shù)據(jù)庫(kù)系統(tǒng)往往都會(huì)使用并發(fā)控制機(jī)制盡可能地充分利用機(jī)器的效率涕俗,最常見的幾種并發(fā)控制機(jī)制就是鎖、時(shí)間戳和 MVCC神帅。
作為悲觀并發(fā)控制機(jī)制再姑,鎖使用在更新資源之前對(duì)資源進(jìn)行鎖定的方式保證多個(gè)數(shù)據(jù)庫(kù)的會(huì)話同時(shí)修改某一行記錄時(shí)不會(huì)出現(xiàn)脫離預(yù)期的行為,而時(shí)間戳這種方式在每次提交時(shí)對(duì)資源是否被改變進(jìn)行檢查找御。
分布式事務(wù)
從單機(jī)的數(shù)據(jù)庫(kù)事務(wù)變成分布式事務(wù)時(shí)元镀,原有單機(jī)中相對(duì)可靠的方法調(diào)用以及進(jìn)程間通信方式已經(jīng)沒有辦法使用,同時(shí)由于網(wǎng)絡(luò)通信經(jīng)常是不穩(wěn)定的霎桅,所以服務(wù)之間信息的傳遞會(huì)出現(xiàn)障礙栖疑。
當(dāng)我們通過(guò)網(wǎng)絡(luò)請(qǐng)求其他服務(wù)的接口時(shí),往往會(huì)得到三種結(jié)果:正確滔驶、失敗和超時(shí)遇革,無(wú)論是成功還是失敗,我們都能得到唯一確定的結(jié)果,超時(shí)代表請(qǐng)求的發(fā)起者不能確定接受者是否成功處理了請(qǐng)求萝快,這也是造成諸多問(wèn)題的誘因锻霎。
系統(tǒng)之間的通信可靠性從單一系統(tǒng)中的可靠變成了微服務(wù)架構(gòu)之間的不可靠,分布式事務(wù)其實(shí)就是在不可靠的通信下實(shí)現(xiàn)事務(wù)的特性揪漩。無(wú)論是事務(wù)還是分布式事務(wù)實(shí)現(xiàn)原子性都無(wú)法避免對(duì)持久存儲(chǔ)的依賴旋恼,事務(wù)使用磁盤上的日志記錄執(zhí)行的過(guò)程以及上下文,這樣無(wú)論是需要回滾還是補(bǔ)償都可以通過(guò)日志追溯氢拥,而分布式事務(wù)也會(huì)依賴數(shù)據(jù)庫(kù)蚌铜、Zookeeper 或者 ETCD 等服務(wù)追蹤事務(wù)的執(zhí)行過(guò)程,總而言之嫩海,各種形式的日志是保證事務(wù)幾大特性的重要手段冬殃。
2PC 與 3PC
-
2PC
兩階段提交的執(zhí)行過(guò)程就跟它的名字一樣分為兩個(gè)階段,投票階段和提交階段叁怪,在投票階段中审葬,協(xié)調(diào)者(Coordinator)會(huì)向事務(wù)的參與者(Cohort)詢問(wèn)是否可以執(zhí)行操作的請(qǐng)求,并等待其他參與者的響應(yīng)奕谭,參與者會(huì)執(zhí)行相對(duì)應(yīng)的事務(wù)操作并記錄重做和回滾日志涣觉,所有執(zhí)行成功的參與者會(huì)向協(xié)調(diào)者發(fā)送 AGREEMENT 或者 ABORT 表示執(zhí)行操作的結(jié)果。
當(dāng)所有的參與者都返回了確定的結(jié)果(同意或者終止)時(shí)血柳,兩階段提交就進(jìn)入了提交階段官册,協(xié)調(diào)者會(huì)根據(jù)投票階段的返回情況向所有的參與者發(fā)送提交或者回滾的指令。
當(dāng)事務(wù)的所有參與者都決定提交事務(wù)時(shí)难捌,協(xié)調(diào)者會(huì)向參與者發(fā)送 COMMIT 請(qǐng)求膝宁,參與者在完成操作并釋放資源之后向協(xié)調(diào)者返回完成消息,協(xié)調(diào)者在收到所有參與者的完成消息時(shí)會(huì)結(jié)束整個(gè)事務(wù)员淫;與之相反击敌,當(dāng)有參與者決定 ABORT 當(dāng)前事務(wù)時(shí),協(xié)調(diào)者會(huì)向事務(wù)的參與者發(fā)送回滾請(qǐng)求圣蝎,參與者會(huì)根據(jù)之前執(zhí)行操作時(shí)的回滾日志對(duì)操作進(jìn)行回滾并向協(xié)調(diào)者發(fā)送完成的消息衡瓶,在提交階段,無(wú)論當(dāng)前事務(wù)被提交還是回滾步淹,所有的資源都會(huì)被釋放并且事務(wù)也一定會(huì)結(jié)束。
-
3PC
為了解決兩階段提交在協(xié)議的一些問(wèn)題键闺,三階段提交引入了超時(shí)機(jī)制和準(zhǔn)備階段辛燥,如果協(xié)調(diào)者或者參與者在規(guī)定的之間內(nèi)沒有接受到來(lái)自其他節(jié)點(diǎn)的響應(yīng)缝其,就會(huì)根據(jù)當(dāng)前的狀態(tài)選擇提交或者終止整個(gè)事務(wù),準(zhǔn)備階段的引入其實(shí)讓事務(wù)的參與者有了除回滾之外的其他選擇榴都。
當(dāng)參與者向協(xié)調(diào)者發(fā)送 ACK 后漠其,如果長(zhǎng)時(shí)間沒有得到協(xié)調(diào)者的響應(yīng),在默認(rèn)情況下拴驮,參與者會(huì)自動(dòng)將超時(shí)的事務(wù)進(jìn)行提交柴信,不會(huì)像兩階段提交中被阻塞住潜沦;上述的圖片非常清楚地說(shuō)明了在不同階段,協(xié)調(diào)者或者參與者的超時(shí)會(huì)造成什么樣的行為。
Saga
兩階段提交其實(shí)可以保證事務(wù)的強(qiáng)一致性窃判,但是在很多業(yè)務(wù)場(chǎng)景下,我們其實(shí)只需要保證業(yè)務(wù)的最終一致性询件,在一定的時(shí)間窗口內(nèi)唆樊,多個(gè)系統(tǒng)中的數(shù)據(jù)不一致是可以接受的,在過(guò)了時(shí)間窗口之后嘿辟,所有系統(tǒng)都會(huì)返回一致的結(jié)果。
Saga 其實(shí)就一種簡(jiǎn)化的分布式事務(wù)解決方案红伦,它將一系列的分布式操作轉(zhuǎn)化成了一系列的本地事務(wù),在每一個(gè)本地事務(wù)中我們都會(huì)更新數(shù)據(jù)庫(kù)并且向集群中的其他服務(wù)發(fā)送一條的新的消息來(lái)觸發(fā)下一個(gè)本地的事務(wù)召调;一旦本地的事務(wù)因?yàn)檫`反了業(yè)務(wù)邏輯而失敗,那么就會(huì)立刻觸發(fā)一系列的回滾操作來(lái)撤回之前本地事務(wù)造成的副作用唠叛。
Saga 這種模式其實(shí)完全放棄了同時(shí)滿足事務(wù)四大基本特性 ACID 的想法沮稚,而是選擇降低實(shí)現(xiàn)分布式事務(wù)的難度并減少資源同步以及鎖定帶來(lái)的問(wèn)題,選擇實(shí)現(xiàn) BASE(Basic Availability, Soft, Eventual consistency) 事務(wù)澳厢,達(dá)到業(yè)務(wù)上的基本可用以及最終一致性囚似,在絕大多數(shù)的業(yè)務(wù)場(chǎng)景中,實(shí)現(xiàn)最終一致性就能夠基本滿足業(yè)務(wù)的全部需求徐伐,極端場(chǎng)景下還是應(yīng)該選擇兩階段提交或者干脆放棄分布式事務(wù)這種易錯(cuò)的實(shí)現(xiàn)方式募狂,轉(zhuǎn)而使用單機(jī)中的數(shù)據(jù)庫(kù)事務(wù)來(lái)解決。
消息服務(wù)
分布式事務(wù)帶來(lái)復(fù)雜度的原因其實(shí)就是由于各個(gè)模塊之間的通信不穩(wěn)定祸穷,當(dāng)我們發(fā)出一個(gè)網(wǎng)絡(luò)請(qǐng)求時(shí),可能的返回結(jié)果是成功需曾、失敗或者超時(shí)祈远。
網(wǎng)絡(luò)無(wú)論是返回成功還是失敗其實(shí)都是一個(gè)確定的結(jié)果,當(dāng)網(wǎng)絡(luò)請(qǐng)求超時(shí)的時(shí)候其實(shí)非常不好處理谋减,在這時(shí)調(diào)用方并不能確定這一次請(qǐng)求是否送達(dá)而且不會(huì)知道請(qǐng)求的結(jié)果扫沼,但是消息服務(wù)可以保證某條信息一定會(huì)送達(dá)到調(diào)用方庄吼;大多數(shù)消息服務(wù)都會(huì)提供兩種不同的 QoS以政,也就是服務(wù)的等級(jí)。
最常見的兩種服務(wù)等級(jí)就是 At-Most-Once 和 At-Least-Once废菱,前者能夠保證發(fā)送方不對(duì)接收方是否能收到消息作保證抖誉,消息要么會(huì)被投遞一次,要么不會(huì)被投遞旁理,這其實(shí)跟一次普通的網(wǎng)絡(luò)請(qǐng)求沒有太多的區(qū)別我磁;At-Least-Once 能夠解決消息投遞失敗的問(wèn)題,它要求發(fā)送者檢查投遞的結(jié)果夺艰,并在失敗或者超時(shí)時(shí)重新對(duì)消息進(jìn)行投遞,發(fā)送者會(huì)持續(xù)對(duì)消息進(jìn)行推送减牺,直到接受者確認(rèn)消息已經(jīng)被收到存谎,相比于 At-Most-Once,At-Least-Once 因?yàn)槟軌虼_保消息的投遞會(huì)被更多人使用稚失。
除了這兩種常見的服務(wù)等級(jí)之外,還有另一種服務(wù)等級(jí)句各,也就是 Exactly-Once憨琳,這種服務(wù)等級(jí)不僅對(duì)發(fā)送者提出了要求旬昭,還對(duì)消費(fèi)者提出了要求,它需要接受者對(duì)接收到的所有消息進(jìn)行去重遍略,發(fā)送者和接受者一方對(duì)消息進(jìn)行重試惧所,另一方對(duì)消息進(jìn)行去重下愈,兩者分別部署在不同的節(jié)點(diǎn)上蕾久,這樣對(duì)于各個(gè)節(jié)點(diǎn)上的服務(wù)來(lái)說(shuō),它們之間的通信就是 Exactly-Once 的履因,但是需要注意的是,Exacly-Once 一定需要接收方的參與栅迄。
我們可以通過(guò)實(shí)現(xiàn) AMQP 協(xié)議的消息隊(duì)列來(lái)實(shí)現(xiàn)分布式事務(wù)皆怕,在協(xié)議的標(biāo)準(zhǔn)中定義了 tx_select、tx_commit 和 tx_rollback 三個(gè)事務(wù)相關(guān)的接口憋活,其中 tx_select 能夠開啟事務(wù)顶滩,tx_commit 和 tx_rollback 分別能夠提交或者回滾事務(wù)。
使用消息服務(wù)實(shí)現(xiàn)分布式事務(wù)在底層的原理上與其他的方法沒有太多的差別盐欺,只是消息服務(wù)能夠幫助我們實(shí)現(xiàn)的消息的持久化以及重試等功能仅醇,能夠?yàn)槲覀兲峁┮粋€(gè)比較合理的 API 接口,方便開發(fā)者使用析二。