溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring中如何實(shí)現(xiàn)分布式事務(wù)

發(fā)布時(shí)間:2021-08-09 11:55:44 來(lái)源:億速云 閱讀:300 作者:Leah 欄目:大數(shù)據(jù)

本篇文章給大家分享的是有關(guān)Spring中如何實(shí)現(xiàn)分布式事務(wù),小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

分布式系統(tǒng)的實(shí)現(xiàn)原則

那么在分布式系統(tǒng)當(dāng)中,我們應(yīng)該怎么樣去實(shí)現(xiàn)事務(wù)呢?這就需要從分布式系統(tǒng)的原則說(shuō)起。分布式系統(tǒng)的實(shí)現(xiàn)原則有幾種說(shuō)法,如BASE原理、ACP原理。
其中ACP是:

  • A: 可用性(Availability)

  • C: 一致性(Consistency)

  • P: 分區(qū)容錯(cuò)性(Tolerance of network Partition)

A和P沒(méi)什么好說(shuō)的,就是分布式系統(tǒng)的基本特性,C(一致性)就是指在分布式系統(tǒng)當(dāng)中,多個(gè)節(jié)點(diǎn)之間數(shù)據(jù)的一致性,包括一個(gè)節(jié)點(diǎn)修改的數(shù)據(jù),通過(guò)另一個(gè)節(jié)點(diǎn)訪問(wèn)的時(shí)候也能看到;以及當(dāng)一個(gè)操作需要修改多個(gè)數(shù)據(jù)源的數(shù)據(jù)的時(shí)候,多個(gè)修改要都能夠完成,或者都不完成。

這里的一致性,我們可以看做是上面說(shuō)的數(shù)據(jù)庫(kù)事務(wù)的ACID特性中,原子性、一致性,甚至是隔離性的統(tǒng)一。如果以ACID這4個(gè)特性為要求來(lái)實(shí)現(xiàn)分布式系統(tǒng),在現(xiàn)實(shí)當(dāng)中是不可能的,其中原子性就沒(méi)有辦法實(shí)現(xiàn)。如果一個(gè)業(yè)務(wù)請(qǐng)求,要修改多個(gè)數(shù)據(jù)庫(kù)中的數(shù)據(jù),那么這多個(gè)數(shù)據(jù)庫(kù)的操作,就無(wú)法實(shí)現(xiàn)原子性,勢(shì)必會(huì)有一個(gè)先后,在第一個(gè)數(shù)據(jù)庫(kù)上完成以后,再在第二個(gè)數(shù)據(jù)庫(kù)上完成,那么這期間的一點(diǎn)點(diǎn)時(shí)間,就違反了原子性。

所以,我們往往無(wú)法在分布式系統(tǒng)中實(shí)現(xiàn)完全的一致性,所以就有了BASE理論。BASE是Basically Available(基本可用)、Soft state(軟狀態(tài))和Eventually consistent(最終一致性)三個(gè)短語(yǔ)的縮寫(xiě)。BASE理論是對(duì)CAP中一致性和可用性權(quán)衡的結(jié)果,要求實(shí)現(xiàn)最終一致性即可。

其中,Soft state(軟狀態(tài))是指,在一個(gè)業(yè)務(wù)操作過(guò)程中,允許出現(xiàn)一個(gè)中間狀態(tài),也就是軟狀態(tài),而不要求原子性那樣,要么都完成,要么都不完成。例如在下單的時(shí)候,出現(xiàn)一個(gè)“正在處理”的狀態(tài)。由于有這個(gè)軟狀態(tài),那我的一致性,就不要求是強(qiáng)一致性,而是最終一致性,也就是說(shuō),只要最終這個(gè)請(qǐng)求能處理完,所有的數(shù)據(jù)狀態(tài)都是處理完的狀態(tài);如果期間出錯(cuò)了,所有的數(shù)據(jù)也都一致,該失敗的失敗、該退錢(qián)的退錢(qián)、該重置的重置。

分布式事務(wù)的實(shí)現(xiàn)

所以,確定了分布式系統(tǒng)的實(shí)現(xiàn)原則是最終一致性以后,同時(shí)也明確了我們實(shí)現(xiàn)分布式事務(wù)的原則,也是最終一致性。
其實(shí),不管是數(shù)據(jù)庫(kù)事務(wù)的ACID特性,還是分布式事務(wù)的最終一致性,其實(shí),都是根據(jù)事務(wù)的定義和它的兩個(gè)目標(biāo),所采取的不同的實(shí)現(xiàn)方式。

那么我們應(yīng)該怎么實(shí)現(xiàn)這個(gè)最終一致性呢?

單服務(wù)的分布式事務(wù)

首先,任何一個(gè)分布式系統(tǒng),總是由一個(gè)個(gè)的系統(tǒng)組成,也就是一個(gè)個(gè)的服務(wù),這些服務(wù)又可以部署多個(gè)。同時(shí),我們的整個(gè)系統(tǒng)也需要一定的方式相互作用、相關(guān)通信。有時(shí)候,我們可以讓一個(gè)服務(wù)直接調(diào)用另一個(gè)服務(wù)的接口(如果有提供的話);還有時(shí)候,我們可以讓兩個(gè)服務(wù)通過(guò)一個(gè)MQ之類(lèi)的消息中間件通信,共同完成一些業(yè)務(wù)。但是,無(wú)論如何,大部分情況下,分布式系統(tǒng)的一個(gè)服務(wù)總是會(huì)訪問(wèn)多個(gè)數(shù)據(jù)源。最典型的例子就是通過(guò)MQ接受一個(gè)事件,然后出發(fā)一些操作,再把結(jié)果發(fā)送到另一個(gè)隊(duì)列里。

對(duì)于這種每個(gè)服務(wù)訪問(wèn)多個(gè)數(shù)據(jù)源的情況,其實(shí)就是一個(gè)最簡(jiǎn)單的分布式事務(wù)的場(chǎng)景。如果大家在網(wǎng)上搜“Spring分布式事務(wù)實(shí)現(xiàn)”,搜到的結(jié)果也都是在說(shuō)這個(gè)場(chǎng)景下的分布式事務(wù)實(shí)現(xiàn)過(guò)程。

要實(shí)現(xiàn)這個(gè)事務(wù),首先需要對(duì)Spring的事物機(jī)制有一定了解。對(duì)于這種情況,最簡(jiǎn)單的就是使用Spring的JTA事務(wù)管理。但是,我們知道,JTA事務(wù)管理是通過(guò)兩階段提交實(shí)現(xiàn)的,在很多情況下,它的效率是很低的。因?yàn)樗诙鄠€(gè)數(shù)據(jù)源修改數(shù)據(jù)的時(shí)候,這些數(shù)據(jù)一直都處在被鎖的狀態(tài),知道多個(gè)數(shù)據(jù)源的事務(wù)都提交完成,才會(huì)釋放。

如果不用JTA,Spring也給我們提供了幾種方式,來(lái)近似的實(shí)現(xiàn)分布式事務(wù)(注意這里說(shuō)的近似)。例如:

  1. 事務(wù)同步,也就是提交一個(gè)事物的時(shí)候,通過(guò)Listener等方式通知另一個(gè)事務(wù)也提交。但是這種情況下,如果第二個(gè)事務(wù)提交的時(shí)候出錯(cuò)了,第一個(gè)事物就無(wú)法回滾,因?yàn)樗呀?jīng)提交完成了。

  2. 鏈?zhǔn)绞聞?wù),就是將多個(gè)事務(wù),包裝在一個(gè)鏈?zhǔn)绞聞?wù)管理器當(dāng)中,在提交事務(wù)的時(shí)候,一次提交里面的事務(wù)。對(duì)于這種實(shí)現(xiàn),也存在上面說(shuō)的問(wèn)題。

  3. 還有其他的一些方式,就不過(guò)多說(shuō)明。

所以,使用Spring在單服務(wù)多數(shù)據(jù)源的情況下,實(shí)現(xiàn)分布式事務(wù),實(shí)際上沒(méi)辦法完全實(shí)現(xiàn)事務(wù)的,因?yàn)槌鲥e(cuò)的時(shí)候不能保證都會(huì)滾。那么這時(shí)候,就需要再通過(guò)其他機(jī)制來(lái)補(bǔ)充。

  1. 首先就是重試,也就是在出錯(cuò)的時(shí)候,重試之前的操作。這在有MQ的時(shí)候比較常用,因?yàn)橐话愕腗Q服務(wù)器,在你讀消息以后,處理的時(shí)候如果出錯(cuò)了,那么這個(gè)讀消息的操作不會(huì)被提交。那這個(gè)消息就會(huì)被重新讀到,重新出發(fā)剛才的操作。這時(shí)候,我們就需要考慮這個(gè)方法的冪等性,保證在重復(fù)消息的時(shí)候不會(huì)重復(fù)處理數(shù)據(jù)。

  2. 其次,我們需要自己處理一些錯(cuò)誤。例如上面的情況,重試幾次以后,一直沒(méi)有成功,那么這時(shí)候就需要走失敗邏輯。有時(shí)候,我們也可以通過(guò)一個(gè)定時(shí)器來(lái)檢查一定時(shí)間內(nèi)沒(méi)有完成的失敗操作。

  3. 有些情況下,我們還需要考慮其他各種錯(cuò)誤,如網(wǎng)絡(luò)錯(cuò)誤、超時(shí),系統(tǒng)宕機(jī)等等。

大家可以試想一下,分布式系統(tǒng)越復(fù)雜,它的各種出錯(cuò)的情況就越多,我們需要考慮的補(bǔ)救措施就越多。那這種修修補(bǔ)補(bǔ)的實(shí)現(xiàn)分布式事務(wù)的最終一致性的做法,始終不是一個(gè)好的辦法。但是,使用Spring解決單服務(wù)的分布式系統(tǒng),始終是分布式事務(wù)實(shí)現(xiàn)的基礎(chǔ)。我們可以用其他的模式來(lái)方便我們解決分布式事務(wù),但是在每個(gè)服務(wù)當(dāng)中,我們還是要經(jīng)常使用事務(wù)同步、鏈?zhǔn)绞聞?wù)等,來(lái)實(shí)現(xiàn)事務(wù)。我們用Spring來(lái)保證絕大多數(shù)情況下的事務(wù)問(wèn)題,而對(duì)于特殊的錯(cuò)誤情況,就采用其他的模式來(lái)解決。

分布式事務(wù)實(shí)現(xiàn)的模式

剛才說(shuō)了我們用其他模式來(lái)覺(jué)得分布式事務(wù)問(wèn)題,那么都有什么模式呢?

消息驅(qū)動(dòng)(Event Driven)模式

消息驅(qū)動(dòng)模式是,當(dāng)某個(gè)業(yè)務(wù)請(qǐng)求需要由多個(gè)服務(wù)參與完成的時(shí)候,這些服務(wù)之前不直接通信,而是通過(guò)一個(gè)MQ中間件來(lái)通信。比如對(duì)于一個(gè)訂單支付的請(qǐng)求,接收到支付完成的請(qǐng)求后,通過(guò)MQ,通知訂單服務(wù)去完成訂單,訂單服務(wù)再去通知商品服務(wù)去減庫(kù)存,再通知物流服務(wù)去發(fā)起物流流程。

那么,對(duì)于每一個(gè)服務(wù)來(lái)說(shuō),都需要先從一個(gè)隊(duì)列讀取一個(gè)消息,完成自己的業(yè)務(wù)操作,再往另一個(gè)隊(duì)列發(fā)送一個(gè)消息,這就需要操作一個(gè)數(shù)據(jù)和一個(gè)MQ服務(wù)器。這也就是上面說(shuō)的單服務(wù)的分布式事務(wù)實(shí)現(xiàn)。對(duì)于這種模式而言,我們用事務(wù)同步保證在每個(gè)服務(wù)中,在大部分情況下都能保證事務(wù)。即使偶爾出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤、系統(tǒng)錯(cuò)誤等,通過(guò)重試就能解決大部分問(wèn)題。如果重試一直不能解決,那就再處理失敗邏輯。

我們使用這種方式,最重要的,就是對(duì)這個(gè)消息、和他的處理流程的編排,其次,它也是一種響應(yīng)式的編程思維。

事件溯源(Event Sourcing)模式

Event Sourcing在上面說(shuō)的消息驅(qū)動(dòng)的基礎(chǔ)上,進(jìn)一步提升事件(也就是之前的消息)的地位,讓它成為系統(tǒng)的一等公民。也就是說(shuō),怎么的系統(tǒng)不是基于原先那些實(shí)體的,而是基于事件的,一個(gè)事件就代表一個(gè)業(yè)務(wù)操作和業(yè)務(wù)數(shù)據(jù)狀態(tài)的更改。至于業(yè)務(wù)數(shù)據(jù),我們不需要把它保存在數(shù)據(jù)庫(kù)中,即使保存,也只是為了查詢數(shù)據(jù)方便而保存。

在Event Sourcing模式中,每個(gè)服務(wù)完成某個(gè)邏輯的方式,跟上面說(shuō)的消息驅(qū)動(dòng)模式差不多,就是對(duì)于用戶的每個(gè)操作,會(huì)產(chǎn)生一個(gè)事件(可能多個(gè)),這個(gè)事件會(huì)被某個(gè)服務(wù)的某個(gè)處理方法處理,它也有可能再產(chǎn)生其他的事件,再由其他服務(wù)處理,直到完成整個(gè)業(yè)務(wù)流程。但是,它跟消息驅(qū)動(dòng)的最大區(qū)別就是,在Event Sourcing的服務(wù)里,業(yè)務(wù)狀態(tài)數(shù)據(jù)不一定要保存在數(shù)據(jù)庫(kù)中,就算保存,出錯(cuò)了也沒(méi)關(guān)系,反正它可以根據(jù)Event事件重新生成。所以這個(gè)地方的事務(wù),我們只需要保證Event保存成功即可。當(dāng)然,我們需要其他的機(jī)制,方便我們能夠重新生成業(yè)務(wù)數(shù)據(jù),而這,一般都是實(shí)現(xiàn)Event Sourcing的框架來(lái)提供。

TCC(Try-Confirm-Cancel)模式

除了上面說(shuō)的通過(guò)一個(gè)中間價(jià)關(guān)聯(lián)不同的服務(wù),在有些分布式系統(tǒng)當(dāng)中,我們的不同的服務(wù)可以直接通信,例如Spring Cloud微服務(wù)框架就提供Rest方式訪問(wèn)別的服務(wù)。那么這時(shí)候,就相當(dāng)于,我的一個(gè)服務(wù)除了訪問(wèn)自己的數(shù)據(jù)庫(kù)以外,還要訪問(wèn)別的服務(wù),這里的這個(gè)服務(wù)就可以當(dāng)做是一個(gè)數(shù)據(jù)庫(kù)。我們可能要調(diào)用別的服務(wù)的某個(gè)接口完成一些業(yè)務(wù)。

在這種情況下,一個(gè)服務(wù)提供的接口,不可能實(shí)現(xiàn)事務(wù),也就是先操作數(shù)據(jù),再Commit,如果出錯(cuò)了再Rollback。但是,我們可以借鑒事務(wù)的這種處理思路,來(lái)自己提供類(lèi)似事務(wù)的方法,這就是TCC模式。一個(gè)事物是通過(guò)Do-Commit/Rollback來(lái)實(shí)現(xiàn)的,在TCC模式中,是通過(guò)給每一個(gè)服務(wù)間調(diào)用的操作接口,提供一套Try-Confirm/Cancel接口。

還是舉一個(gè)例子,就是用戶下單以后支付完成。支付完成的時(shí)候由先訂單服務(wù)處理,然后調(diào)用商品服務(wù)去減庫(kù)存。大家用Spring Cloud的話,可能就在商品服務(wù)里寫(xiě)一個(gè)接口直接做減庫(kù)存的操作,但是在TCC模式下,我們需要3個(gè)接口。首先是減庫(kù)存的Try接口,在這里,我們要檢查業(yè)務(wù)數(shù)據(jù)的狀態(tài)、檢查商品庫(kù)存夠不夠,然后做資源的預(yù)留,也就是在某個(gè)字段上設(shè)置預(yù)留的狀態(tài)。然后在Confirm接口里,完成庫(kù)存減1的操作。在Cancel接口里,把之前預(yù)留的字段重置。

這可能聽(tīng)著有點(diǎn)繁瑣,感覺(jué)可以一次完成的事情,為什么要分成2步,首先這么做是為了能夠在出錯(cuò)的時(shí)候正確的重置庫(kù)存數(shù)據(jù),其次這個(gè)預(yù)留操作跟Confirm操作是兩個(gè)請(qǐng)求,中間可能會(huì)有其他并發(fā)請(qǐng)求。從理論上說(shuō),只要我們?cè)赥ry接口里面預(yù)留資源的邏輯是正確的,那么,即使Confirm的時(shí)候出錯(cuò)了,我也可以通過(guò)重試Confirm請(qǐng)求來(lái)完成

使用數(shù)據(jù)庫(kù)保存事務(wù)狀態(tài)

這其實(shí)不是一種模式,只是一種方式。例如在TCC模式下,在準(zhǔn)備調(diào)用Confirm接口的時(shí)候,目標(biāo)服務(wù)突然宕機(jī)了,或者發(fā)起請(qǐng)求的服務(wù)突然宕機(jī)或出錯(cuò)了,導(dǎo)致這個(gè)Confirm請(qǐng)求一直沒(méi)有被調(diào)用。那么,在系統(tǒng)恢復(fù)以后,我該怎么完成之前的事務(wù)呢?除了上面說(shuō)的用定時(shí)器定期檢查未完成的操作以外(需要能夠通過(guò)某種數(shù)據(jù)狀態(tài)判斷業(yè)務(wù)沒(méi)有執(zhí)行完成后),我們還可以用數(shù)據(jù)庫(kù)來(lái)記錄事務(wù)的運(yùn)行狀態(tài)。

例如在TCC模式中,每當(dāng)一個(gè)服務(wù)A要使用TCC模式調(diào)用另一個(gè)服務(wù)B的時(shí)候,服務(wù)A將這個(gè)TCC的事務(wù)狀態(tài)寫(xiě)到數(shù)據(jù)庫(kù)中,根據(jù)具體實(shí)現(xiàn),可能是在調(diào)用前記錄當(dāng)前事務(wù)的狀態(tài),調(diào)用完成再保存該調(diào)用的參數(shù)和結(jié)果狀態(tài),這個(gè)事務(wù)完成以后(也就是調(diào)用完Confirm,或Cancel以后),再更新成完成的狀態(tài)。那么,通過(guò)合理的設(shè)計(jì),我們就能在各種出錯(cuò)情況下,保證能繼續(xù)完成這個(gè)事務(wù),或取消這個(gè)事務(wù)。

以上就是Spring中如何實(shí)現(xiàn)分布式事務(wù),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI