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

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

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了長泰免費建站歡迎大家使用!

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

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

  • A: 可用性(Availability)

  • C: 一致性(Consistency)

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. 事務(wù)同步,也就是提交一個事物的時候,通過Listener等方式通知另一個事務(wù)也提交。但是這種情況下,如果第二個事務(wù)提交的時候出錯了,第一個事物就無法回滾,因為他已經(jīng)提交完成了。

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

  3. 還有其他的一些方式,就不過多說明。

所以,使用Spring在單服務(wù)多數(shù)據(jù)源的情況下,實現(xiàn)分布式事務(wù),實際上沒辦法完全實現(xiàn)事務(wù)的,因為出錯的時候不能保證都會滾。那么這時候,就需要再通過其他機制來補充。

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

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

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

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

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

剛才說了我們用其他模式來覺得分布式事務(wù)問題,那么都有什么模式呢?

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

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

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

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

事件溯源(Event Sourcing)模式

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

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

TCC(Try-Confirm-Cancel)模式

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

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

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

這可能聽著有點繁瑣,感覺可以一次完成的事情,為什么要分成2步,首先這么做是為了能夠在出錯的時候正確的重置庫存數(shù)據(jù),其次這個預(yù)留操作跟Confirm操作是兩個請求,中間可能會有其他并發(fā)請求。從理論上說,只要我們在Try接口里面預(yù)留資源的邏輯是正確的,那么,即使Confirm的時候出錯了,我也可以通過重試Confirm請求來完成

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

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

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

以上就是Spring中如何實現(xiàn)分布式事務(wù),小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

當(dāng)前題目:Spring中如何實現(xiàn)分布式事務(wù)
瀏覽路徑:http://muchs.cn/article40/gdohho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、手機網(wǎng)站建設(shè)微信公眾號、網(wǎng)站設(shè)計公司、關(guān)鍵詞優(yōu)化、微信小程序

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)