別再說你不知道分布式事務了
簡介
我們都知道 Seata 是一個分布式事務的解決方案,今天我們就來帶大家了解一下什么是分布式事務,首先我們先來了解一下基礎的知識——事務,我們先來了解一下事務的概念是什么。
基本概念
事務四部分構成— ACID:
- A(Atomic):原子性,構成事務的所有操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗,不會出現(xiàn)部分成功或者部分失敗的情況。
- C(Consistency):一致性,在事務執(zhí)行前后,數(shù)據(jù)庫的一致性約束沒有被破壞,比如,小勇去銀行取100塊錢,取之前是600,取之后應該是400,取之前和取之后的數(shù)據(jù)為正確數(shù)值為一致性,如果取出100,而銀行里面的錢沒有減少,要么小勇要笑醒了,這個就沒有達到一致性的要求。
- I(Isolation):隔離性,數(shù)據(jù)庫中的事務一般都是并發(fā)的,隔離性是只在并發(fā)的兩個事務執(zhí)行過程互不干擾,一個事務在執(zhí)行過程中不能看到其他事務運行過程的中間狀態(tài),通過配置事務隔離級別可以避免臟讀,重復讀等問題。
- D(Durability):持久性,當事務完成之后,事務對數(shù)據(jù)的更改會被持久化到數(shù)據(jù)庫,且不會回滾。
事務分為兩部分:本地事務和分布式事務。
本地事務:
在計算機系統(tǒng)中,比較多的是通過關系型數(shù)據(jù)庫來控制事務,這是利用數(shù)據(jù)庫本身的事務特性進行實現(xiàn)的,因為應用主要靠關系型數(shù)據(jù)庫來維持事務,加上數(shù)據(jù)庫和應用都在同一個服務器,所以基于關系型數(shù)據(jù)的事務又被稱為本地事務。
分布式事務:
分布式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理者分別位于不同的分布式系統(tǒng)的不同節(jié)點之上,且屬于不同的應用,分布式事務需要保證這些操作要么全部成功,要么全部失敗,分布式事務就是為了保證在不同服務器上數(shù)據(jù)庫數(shù)據(jù)的一致性。
Seata 的設計思路是將多個服務器的本地事務組成一個全局事務,下面若干個本地事務,都能滿足ACID,最好形成一個整的分布式事務,操作分布式事務就像是操作本地事務一樣。
分布式系統(tǒng)會把一個應用拆分為多個可獨立部署的服務,服務于服務之間通常需要遠程協(xié)作才能完成事務的操作,這種分布式系統(tǒng)環(huán)境下由于不同的服務之間通過網(wǎng)絡遠程協(xié)作完成的事務被稱為分布式事務,例如供應鏈系統(tǒng)中,訂單創(chuàng)建(生成訂單、扣減庫存、履約通知發(fā)貨)等。
在上圖中我們可以看出,只要涉及到操作多個數(shù)據(jù)源,就會產(chǎn)生事務的問題,我們在實際開發(fā)中應該要避免這這個你問題的出現(xiàn),但是雖然系統(tǒng)的拓展,應用和應用之間必然會產(chǎn)生應用之間事務的分離,當微服務架構中,主要有MQ和Seata,在了解他們之前,我們先來了解一下分布式事務是怎樣組成,以及如何實現(xiàn)的。
分布式事務
分布式事務是什么?
分布式事務指的是事務的參與者,支持事務的服務器,資源服務器分別位于分布式系統(tǒng)的不同節(jié)點之上,通常一個分布式事物中會涉及到對多個數(shù)據(jù)源或業(yè)務系統(tǒng)的操作。
隨著互聯(lián)網(wǎng)的發(fā)展,從之前的單一項目逐漸向分布式服務做轉(zhuǎn)換,現(xiàn)如今微服務在各個公司已經(jīng)普遍存在,而當時的本地事務已經(jīng)無法滿足分布式應用的要求,因此分布式服務之間事務的協(xié)調(diào)就產(chǎn)生了問題,如果做到多個服務之間事務的操作,能夠像本地事務一樣遵循ACID原則,成為一個難題,但是在大牛們不斷的探索下,終于找到了分布式事務存在兩大理論依據(jù):CAP定律和BASE理論。
CAP定律
CAP定律由一致性(C)、可用性(A)、分區(qū)容錯性(P)組成,在分布式系統(tǒng)中,不可能同時滿足Consistency(一致性)/Availability(可用性)/Partition tolerance(分區(qū)容錯性) 三個特性,最多只能同時滿足其中兩項。
- 一致性(C):在分布式系統(tǒng)中所有的數(shù)據(jù)備份,在同一時刻保持一致的特性,所有的應用節(jié)點訪問的都是同一份最新的數(shù)據(jù)副本。
- 可用性(A): 當集群中一部分節(jié)點故障以后,集群整體能夠響應客戶端的讀寫請求,對數(shù)據(jù)更新具備高可用性。
- 分區(qū)容錯性(P): 如果系統(tǒng)在規(guī)定時間限制內(nèi)不能達成數(shù)據(jù)的一致性,就表示要發(fā)生分區(qū)的情況,當前操作需要在C和A之間做出選擇,讓系統(tǒng)能夠在遇到網(wǎng)絡故障等情況的時候,任然能夠保證對外提供滿足一致性或者可用性的服務。
在上圖中我們可以看到,當我們用戶去購物車里面點擊下單結算的時候,首先會經(jīng)過我們庫存服務,判斷庫存是否足夠,當庫存滿足,扣減庫存以后,我們需要將數(shù)據(jù)同步到其他服務器上,這一步是為了保證數(shù)據(jù)的結果的一致性,這個時候如果網(wǎng)絡產(chǎn)生波動了,我們的系統(tǒng)需要保證分區(qū)容錯性,也就是我們必須容忍網(wǎng)絡所帶來的一些問題,此時想保證一致性,就需要舍棄可用性。
但是如果為了保證高可用性,那么在高并發(fā)的情況下,是無法保證在限定時間內(nèi)給出響應,由于網(wǎng)絡的不可靠,我們的訂單服務可能無法拿到最新的數(shù)據(jù),但是我們要給用戶做出響應,那么也無法保證一致性,所以AP是無法保證強一致性的。
如果既想要保證高可用又想要保證一致性,必須在網(wǎng)絡良好的情況下才能實現(xiàn),那么解決方法只有一個,那就是需要將庫存、訂單、履約放到一起,但是這個就上去了我們微服務的作用,也就不再是分布式系統(tǒng)了。
在分布式系統(tǒng)中,分區(qū)容錯性是必須存在的,我們只能在一致性和可用性上取舍,在這種條件下就誕生了BASE理論。
BASE理論
BASE由 基本可用 (Basically Available)、軟狀態(tài) (Soft state)和 最終一致性 (Eventually consistent) 三個構建而成,是對CAP中一致性和可用性權衡的結果,來源于對互聯(lián)網(wǎng)系統(tǒng)分布式實踐的總結,是基于CAP定理逐步演化而來的,核心四系那個是及時無法做到強一致性,但是每個應用都可以根據(jù)自身的業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性。
- 基本可用:基本可用是指當分布式系統(tǒng)出現(xiàn)不可預知故障的時候,允許損失部分可用性,但是這里并不是說表示系統(tǒng)不可以用,主要體現(xiàn)為以下幾點:
- 響應時間上的損失,在正常情況下,一個在線搜索引擎需要在0.5秒之內(nèi)返回給用戶響應的查詢結果,但是由于出現(xiàn)故障,查詢結果的響應時間增加了1-2秒。
- 系統(tǒng)功能上的損失,在正常情況下,一個電子商務網(wǎng)站上進行購物,消費者幾乎能夠順利的完成每一單操作,但是在一些節(jié)日大促銷購物高峰期的時候,由于網(wǎng)站上購買量的猛增,為了保證系統(tǒng)的穩(wěn)定性,部分消費者可能會引導到一個臨時降級處理的頁面或者提示。
基本可用的意思是,對于我們的核心服務是可以使用的,其他的服務可以適當?shù)慕档晚憫獣r間,甚至是進行服務降級處理,在當前中,庫存和訂單肯定是核心服務,至于我們的發(fā)貨系統(tǒng)在當時只要保證基本可用就行,它的同步可以慢一點或者延遲更高,等待流量高峰過去以后,在進行恢復。
- 軟狀態(tài):軟狀態(tài)是指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認為該中間狀態(tài)的存在不會影響系統(tǒng)的整體可用性,即允許系統(tǒng)不用節(jié)點的數(shù)據(jù)副本之間進行數(shù)據(jù)同步的過程存在延時。
軟狀態(tài)的意思是說,當我們大量下單的時候,扣減庫存時,流量激增,這個時候如果大量訪問到庫存或者訂單中,可能會將系統(tǒng)弄垮,這個過程中我們可以允許數(shù)據(jù)的同步存在延遲,不影響整體系統(tǒng)的使用。
- 最終一致性:最終一致性強調(diào)的是所有數(shù)據(jù)副本,在經(jīng)過一段時間的同步之后,最終都能夠達到一個一致的狀態(tài),因此,最終一致性的本質(zhì)是需要系統(tǒng)保證最終數(shù)據(jù)能夠達到一致,而不是需要實時保證系統(tǒng)的強一致性。
經(jīng)過流量高峰期以后,經(jīng)過一段時間的同步,從中間狀態(tài)最后變成數(shù)據(jù)最終一致性,保證各個服務數(shù)據(jù)的一致性。
二階段提交(2PC)
2PC即兩階段提交協(xié)議,是將整個事務流程分為兩個階段,P是指準備階段,C是指提交階段。
就好比我們?nèi)CC買冰淇淋吃,那剛好有活動,第二杯半價,但是你是一個人,這個時候剛好有個小姐姐過來,正在考慮買不買冰淇淋吃,這個時候你和她提出了AA,也就會說只有當你和她都同意買這個的時候,才能購買到,如果兩個人中有一個不同意那么就不能買這個冰淇淋吃。
階段一:準備階段 老板要求你先進行付款,你同意付款完成后,再要求女方付款,女方同意付款完成。
階段二:提交階段 都付款完成,老板出餐,兩個人都吃到冰淇淋。
這個例子就組成了一個事務。如果男女雙方有一個人拒絕付款,那么老板就不會出餐,并且會把已收取的錢原路退回。
整個事務過程是由事務管理器和參與者組成的,店老板就是事務管理器,你和那個女孩就是參與者,事務管理器決策整個分布式事務在計算機中關系數(shù)據(jù)支持兩階段提交協(xié)議:
- 準備階段(Prepare phase):事務管理器給每個參與者發(fā)送Prepare? 消息,每個數(shù)據(jù)庫參與者在本地執(zhí)行事務,并寫本地的Undo/Redo 日志,此時事務沒有提交。
undo日志是記錄修改前的數(shù)據(jù),用于數(shù)據(jù)庫回滾。
Redo 日志是記錄修改后的數(shù)據(jù),用于提交事務寫入數(shù)據(jù)文件。
- 提交階段(commit phase):如果事務管理器收到了參與者的執(zhí)行失敗或者超時消息時,直接給每個參與者發(fā)送(Rollback?) 消息,如果收到參與者都成功,發(fā)送(Commit) 參與者根據(jù)事務管理器的指令執(zhí)行提交或者回滾操作,并釋放事務處理過程中使用的資源。
成功提交:
事務管理器向所有參與者發(fā)送事務內(nèi)容,詢問是否準備好了,等待參與者的響應,各個參與者事務節(jié)點執(zhí)行事務操作,并將 Undo和Redo 信息記入事務日志中。如果參與者成功執(zhí)行事務操作,反饋事務管理器YES操作,表示事務可以執(zhí)行,假如協(xié)調(diào)者從所有的參與者或得反饋都是Yes響應,那么就會執(zhí)行事務提交。
失?。?/h4>
假如任何一個參與者向事務管理器反饋了No指令,或者等待超時之后,事務管理器無法接收到所有參與者的反饋響應,那么中斷事務,發(fā)送回滾請求,事務管理器向所有參與者節(jié)點發(fā)送 RollBack 請求,參與者接收到 RollBack 請求后,會利用在階段一記錄的Undo信息執(zhí)行事務的回滾操作,在完成回滾之后釋放事務執(zhí)行期間占用的資源,參與者在完成事務回滾之后,向協(xié)調(diào)者發(fā)送ACK消息,事務管理器在接受到所有參與者反饋的ACK消息之后,完成事務中斷。
三階段提交(3PC)
3PC 主要是為了解決兩階段提交協(xié)議的單點故障問題和縮小參與者阻塞范圍。是二階段提交(2PC)的改進版本,引入?yún)⑴c節(jié)點的超時機制之外,3PC把2PC的準備階段分成事務詢問(該階段不會阻塞)和事務預提交,則三個階段分別為 CanCommit、PreCommit、DoCommit。
CanCommit 詢問狀態(tài)
CanCommit階段 協(xié)調(diào)者(Coordinator)會向參與者(Participant) 發(fā)送CanCommit消息,詢問是否可以執(zhí)行操作,參與者收到消息后,表示能夠執(zhí)行,會返回給協(xié)調(diào)者能夠執(zhí)行的(yes)命令。
如果參與者不能執(zhí)行,會返回No命令,釋放資源,結束事務。
PreCommit 預提交
PreCommit 階段如果協(xié)調(diào)者收到參與者返回的狀態(tài)值為YES,那么就證明它們都有能力去執(zhí)行這個操作,那么協(xié)調(diào)者就會向所有參與者 發(fā)送 PreCommit 消息,協(xié)調(diào)者收到 PreCommit消息后,回去執(zhí)行本地事務,如果執(zhí)行成功會將本地事務保存到 undo和redo 后,再返回給協(xié)調(diào)者YES指令,如果執(zhí)行本地事務失敗,返回協(xié)調(diào)者No,只要協(xié)調(diào)者收到一個執(zhí)行失敗,給所有參與者發(fā)送中斷事務消息,參與者收到消息后,對事務進行回滾操作。
在這個階段參與者和協(xié)調(diào)者都引入了超時機制,如果參與者沒有收到,協(xié)調(diào)者的消息,或者協(xié)調(diào)者沒有收到參與者返回的預執(zhí)行結果狀態(tài),在等待超時之后,事務會中斷,避免了事務的阻塞。
協(xié)調(diào)者向參與者發(fā)送PreCommit?,如果參與者執(zhí)行成功,返回yes。
如果參與者執(zhí)行失敗,只有有一個返回No到協(xié)調(diào)者,協(xié)調(diào)者會向參與者發(fā)送中斷事務的消息,參與者回滾事務。
DoCommit 提交
協(xié)調(diào)者收到所有參與者返回的狀態(tài)都是YES,這時協(xié)調(diào)者會向所有的參與者都發(fā)送 DoCommit ,參與者收到 DoCommit 后,會真正的提交事務,當事務提交成功后,返回協(xié)調(diào)者YES狀態(tài),表示我已經(jīng)完成事務的提交了,協(xié)調(diào)者收到所有參與者都返回YES狀態(tài)后,那么就完成了本次事務。
如果某個參與者返回No消息,協(xié)調(diào)者發(fā)送中斷事務消息(abort),給參與者們,參與者回滾事務。
3PC是2PC的升級版,引入了超時機制,解決了單點故障引起的事務阻塞問題,但是3PC依然不能解決事務一致性的問題,因為在DoCommit階段,如果由于網(wǎng)絡或者超時等原則導致參與者收不到協(xié)調(diào)者發(fā)送過來的 中斷事務消息(abort) ,過了這個時間后,參與者會提交事務,本來是應該進行回滾,提交事務后,會導致數(shù)據(jù)不一致的問題出現(xiàn),2PC雖然在網(wǎng)絡故障情況下存在強一致性被破壞的問題,但是故障恢復以后能保證最終一致性,3PC雖然有超時時間,解決了阻塞,提高了可用性,但是犧牲了一致性,如果針對網(wǎng)絡波動問題導致數(shù)據(jù)問題這一點上,2PC是優(yōu)于3PC的。
Seata
官網(wǎng):https://seata.io/zh-cn/docs/overview/what-is-seata.html。
Seata 是一款開源的分布式事務解決方案,致力于提供高性能和簡單易用的分布式事務服務。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案。
在微服務系統(tǒng)中,一般業(yè)務會被拆分成獨立的模塊,在官方提供的結構圖中,我們可以看到當前主要分為三個模塊。
- 庫存服務:對于商品庫存信息進行增加或者減少操作。
- 訂單服務:根據(jù)用戶指定商品生成訂單。
- 賬戶服務:從用戶賬戶中扣除余額,增加積分,維護地址信息等等。
在當前架構中,用戶挑選心儀的商品下單后,需要三個服務來完成操作,每一個服務的內(nèi)部都擁有一個獨立的本地事務來保證當前服務數(shù)據(jù)的強一致性,但是三個服務組成的全局事務一致性就沒辦法進行保證,那么Seata就是來解決這個問題的。
Seata術語
官網(wǎng)地址:https://seata.io/zh-cn/docs/overview/terminology.html。
在了解Seata之前,我們先來了解一下 Seata 幾個關鍵的概念:
- TC(Transaction Coordinator)事務協(xié)調(diào)者:維護全局和分支事務的狀態(tài),驅(qū)動全局事務提交或者回滾。
- TM(Transaction Manager) 事務管理者: 發(fā)起者,同時一個RM的一種,定義全局事務的范圍,開始全局事務,提交或回滾全局事務。
- RM(Resource Manager) 資源管理器: 參與事務的微服務,管理分支事務處理的資源,與TC交談以注冊分支事務和報告分支事務的狀態(tài),并驅(qū)動分支事務提交或回滾。
Seata 2PC
一階段: 業(yè)務數(shù)據(jù)和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。
二階段: 提交異步化,非??焖俚赝瓿伞;貪L通過一階段的回滾日志進行反向補償。
一階段本地事務提交前,需要確保先拿到 全局鎖 。拿不到全局鎖 ,不能提交本地事務。拿全局鎖的嘗試被限制在一定范圍內(nèi),超出范圍將放棄,并回滾本地事務,釋放本地鎖。
在數(shù)據(jù)庫本地事務隔離級別讀已提交或以上的基礎上,Seata(AT 模式)的默認全局隔離級別是 讀未提交。
如果應用在特定場景下,必需要求全局的 讀已提交 ,目前 Seata 的方式是通過 SELECT FOR UPDATE 語句的代理。
Seata執(zhí)行流程分析:
每個RM 使用 DataSourceProxy 鏈接數(shù)據(jù)路,目的是使用 ConnectionProxy ,使用數(shù)據(jù)源和數(shù)據(jù)代理的目的是在第一階段將 undo和業(yè)務數(shù)據(jù)放在一個本地事務中提交,這樣就保存了只要有業(yè)務操作就一定會有dudo日志。
在第一階段中,undo存放了數(shù)據(jù)修改前后修改的值,是為了事務回滾做好準備,在第一階段完成就已經(jīng)將分支事務提交了,也就釋放了鎖資源。
TM開啟全局事務開始,將XID全局事務ID放在事務上下文中,通過feign調(diào)用將XID傳入下游服務器中,每個分支事務將自己的 Branch ID分支事務ID和XID進行關聯(lián)。
在第二階段全局事務提交,TC會通知各個分支參與者提交分支事務,在第一階段已經(jīng)提交了分支事務,在這里各參與者只需要刪除undo即可,并且可以異步執(zhí)行。
如果某一個分支事務異常了,第二階段全局事務回滾操作,TC會通知各個分支參與者回滾分支事務,通過XID和Branch-ID找到對應的回滾日志,通過回滾日志生成的反向SQL執(zhí)行,完成分支事務回滾到之前的狀態(tài)。
Seata 下載安裝
下載地址:https://github.com/seata/seata/releases。
解壓后找到conf目錄。
我們在啟動seata之前,首先要啟動nacos,其實也很簡單,只需要下載nacos后啟動就行,不知道nacos怎么操作的看這里的介紹nacos基礎介紹?,啟動好之后,我們再來啟動seata,bin目錄下seata-server.bat。
如果我們看到8091端口在監(jiān)聽,并且在nacos看到服務注冊上去了,就表示我們seata啟動成功了。
總結
到這里我們關于分布式事務的和seata的介紹就講完了,其實關于分布式還有MQ實現(xiàn)可靠消息最終一致性,MQ主要解決了兩個功能:本地事務與消息發(fā)送的原子性問題。事務參與方接收消息的可靠性。