別再說你不知道分散式事務了

2022-06-18 15:00:54

簡介

我們都知道 Seata 是一個分散式事務的解決方案,今天我們就來帶大家瞭解一下什麼是分散式事務,首先我們先來了解一下基礎的知識——事務,我們先來了解一下事務的概念是什麼。

基本概念

事務四部分構成—— ACID

  • A(Atomic):原子性,構成事務的所有操作,要麼全部執行成功,要麼全部執行失敗,不會出現部分成功或者部分失敗的情況。

  • C(Consistency): 一致性,在事務執行前後,資料庫的一致性約束沒有被破壞,比如,小勇去銀行取100塊錢,取之前是600,取之後應該是400,取之前和取之後的資料為正確數值為一致性,如果取出100,而銀行裡面的錢沒有減少,要麼小勇要笑醒了,這個就沒有達到一致性的要求。

  • I(Isolation):隔離性,資料庫中的事務一般都是並行的,隔離性是隻在並行的兩個事務執行過程互不干擾,一個事務在執行過程中不能看到其他事務執行過程的中間狀態,通過設定事務隔離級別可以避免髒讀,重複讀等問題

  • D(Durability):永續性,當事務完成之後,事務對資料的更改會被持久化到資料庫,且不會回滾

事務分為兩部分:本地事務和分散式事務

本地事務:

在計算機系統中,比較多的是通過關係型資料庫來控制事務,這是利用資料庫本身的事務特性進行實現的,因為應用主要靠關係型資料庫來維持事務,加上資料庫和應用都在同一個伺服器,所以基於關係型資料的事務又被稱為本地事務。

分散式事務:

分散式事務是指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理者分別位於不同的分散式系統的不同節點之上,且屬於不同的應用,分散式事務需要保證這些操作要麼全部成功,要麼全部失敗,分散式事務就是為了保證在不同伺服器上資料庫資料的一致性。

Seata 的設計思路是將多個伺服器的本地事務組成一個全域性事務,下面若干個本地事務,都能滿足ACID,最好形成一個整的分散式事務,操作分散式事務就像是操作本地事務一樣。

分散式系統會把一個應用拆分為多個可獨立部署的服務,服務於服務之間通常需要遠端共同作業才能完成事務的操作,這種分散式系統環境下由於不同的服務之間通過網路遠端共同作業完成的事務被稱為分散式事務,例如供應鏈系統中,訂單建立(生成訂單、扣減庫存、履約通知發貨)等

在上圖中我們可以看出,只要涉及到操作多個資料來源,就會產生事務的問題,我們在實際開發中應該要避免這這個你問題的出現,但是雖然系統的拓展,應用和應用之間必然會產生應用之間事務的分離,當微服務架構中,主要有MQ和Seata,在瞭解他們之前,我們先來了解一下分散式事務是怎樣組成,以及如何實現的。

分散式事務

分散式事務是什麼?

分散式事務指的是事務的參與者,支援事務的伺服器,資源伺服器分別位於分散式系統的不同節點之上,通常一個分散式事物中會涉及到對多個資料來源或業務系統的操作。

隨著網際網路的發展,從之前的單一專案逐漸向分散式服務做轉換,現如今微服務在各個公司已經普遍存在,而當時的本地事務已經無法滿足分散式應用的要求,因此分散式服務之間事務的協調就產生了問題,如果做到多個服務之間事務的操作,能夠像本地事務一樣遵循ACID原則,成為一個難題,但是在大牛們不斷的探索下,終於找到了分散式事務存在兩大理論依據: CAP定律和BASE理論

CAP定律

CAP定律由一致性(C)、可用性(A)、分割區容錯性(P)組成,在分散式系統中,不可能同時滿足Consistency(一致性)/Availability(可用性)/Partition tolerance(分割區容錯性) 三個特性,最多隻能同時滿足其中兩項。

  • 一致性(C):在分散式系統中所有的資料備份,在同一時刻保持一致的特性,所有的應用節點存取的都是同一份最新的資料副本。

  • 可用性(A): 當叢集中一部分節點故障以後,叢集整體能夠響應使用者端的讀寫請求,對資料更新具備高可用性。

  • 分割區容錯性(P): 如果系統在規定時間限制內不能達成資料的一致性,就表示要發生分割區的情況,當前操作需要在C和A之間做出選擇,讓系統能夠在遇到網路故障等情況的時候,任然能夠保證對外提供滿足一致性或者可用性的服務。

在上圖中我們可以看到,當我們使用者去購物車裡麵點選下單結算的時候,首先會經過我們庫存服務,判斷庫存是否足夠,當庫存滿足,扣減庫存以後,我們需要將資料同步到其他伺服器上,這一步是為了保證資料的結果的一致性,這個時候如果網路產生波動了,我們的系統需要保證分割區容錯性,也就是我們必須容忍網路所帶來的一些問題,此時想保證一致性,就需要捨棄可用性。

但是如果為了保證高可用性,那麼在高並行的情況下,是無法保證在限定時間內給出響應,由於網路的不可靠,我們的訂單服務可能無法拿到最新的資料,但是我們要給使用者做出響應,那麼也無法保證一致性,所以AP是無法保證強一致性的

如果既想要保證高可用又想要保證一致性,必須在網路良好的情況下才能實現,那麼解決方法只有一個,那就是需要將庫存、訂單、履約放到一起,但是這個就上去了我們微服務的作用,也就不再是分散式系統了

在分散式系統中,分割區容錯性是必須存在的,我們只能在一致性和可用性上取捨,在這種條件下就誕生了BASE理論

BASE理論

BASE由 基本可用 (Basically Available)、軟狀態 (Soft state)和 最終一致性 (Eventually consistent) 三個構建而成,是對CAP中一致性和可用性權衡的結果,來源於對網際網路系統分散式實踐的總結,是基於CAP定理逐步演化而來的,核心四系那個是及時無法做到強一致性,但是每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性。

  1. 基本可用: 基本可用是指當分散式系統出現不可預知故障的時候,允許損失部分可用性,但是這裡並不是說表示系統不可以用,主要體現為以下幾點:
    • 響應時間上的損失,在正常情況下,一個線上搜尋引擎需要在0.5秒之內返回給使用者響應的查詢結果,但是由於出現故障,查詢結果的響應時間增加了1-2秒

    • 系統功能上的損失,在正常情況下,一個電子商務網站上進行購物,消費者幾乎能夠順利的完成每一單操作,但是在一些節日大促銷購物高峰期的時候,由於網站上購買量的猛增,為了保證系統的穩定性,部分消費者可能會引導到一個臨時降級處理的頁面或者提示

基本可用的意思是,對於我們的核心服務是可以使用的,其他的服務可以適當的降低響應時間,甚至是進行服務降級處理,在當前中,庫存和訂單肯定是核心服務,至於我們的發貨系統在當時只要保證基本可用就行,它的同步可以慢一點或者延遲更高,等待流量高峰過去以後,在進行恢復。

  1. 軟狀態: 軟狀態是指允許系統中的資料存在中間狀態,並認為該中間狀態的存在不會影響系統的整體可用性,即允許系統不用節點的資料副本之間進行資料同步的過程存在延時

軟狀態的意思是說,當我們大量下單的時候,扣減庫存時,流量激增,這個時候如果大量存取到庫存或者訂單中,可能會將系統弄垮,這個過程中我們可以允許資料的同步存在延遲,不影響整體系統的使用。

  1. 最終一致性: 最終一致性強調的是所有資料副本,在經過一段時間的同步之後,最終都能夠達到一個一致的狀態,因此,最終一致性的本質是需要系統保證最終資料能夠達到一致,而不是需要實時保證系統的強一致性。

經過流量高峰期以後,經過一段時間的同步,從中間狀態最後變成資料最終一致性,保證各個服務資料的一致性。

二階段提交(2PC)

2PC即兩階段提交協定,是將整個事務流程分為兩個階段,P是指準備階段,C是指提交階段。

就好比我們去KCC買冰淇淋吃,那剛好有活動,第二杯半價,但是你是一個人,這個時候剛好有個小姐姐過來,正在考慮買不買冰淇淋吃,這個時候你和她提出了AA,也就會說只有當你和她都同意買這個的時候,才能購買到,如果兩個人中有一個不同意那麼就不能買這個冰淇淋吃。

階段一:準備階段 老闆要求你先進行付款,你同意付款完成後,再要求女方付款,女方同意付款完成

階段二:提交階段 都付款完成,老闆出餐,兩個人都吃到冰淇淋

這個例子就組成了一個事務。如果男女雙方有一個人拒絕付款,那麼老闆就不會出餐,並且會把已收取的錢原路退回。

整個事務過程是由事務管理器和參與者組成的,店老闆就是事務管理器,你和那個女孩就是參與者,事務管理器決策整個分散式事務在計算機中關係資料支援兩階段提交協定:

  • 準備階段(Prepare phase):事務管理器給每個參與者傳送 Prepare 訊息,每個資料庫參與者在本地執行事務,並寫原生的 Undo/Redo 紀錄檔,此時事務沒有提交。

undo紀錄檔是記錄修改前的資料,用於資料庫回滾

Redo 紀錄檔是記錄修改後的資料,用於提交事務寫入資料檔案

  • 提交階段(commit phase):如果事務管理器收到了參與者的執行失敗或者超時訊息時,直接給每個參與者傳送(Rollback) 訊息,如果收到參與者都成功,傳送(Commit) 參與者根據事務管理器的指令執行提交或者回滾操作,並釋放事務處理過程中使用的資源。

成功提交:

事務管理器向所有參與者傳送事務內容,詢問是否準備好了,等待參與者的響應,各個參與者事務節點執行事務操作,並將 Undo和Redo 資訊記入事務紀錄檔中。如果參與者成功執行事務操作,反饋事務管理器YES操作,表示事務可以執行,假如協調者從所有的參與者或得反饋都是Yes響應,那麼就會執行事務提交。

失敗:

假如任何一個參與者向事務管理器反饋了No指令,或者等待超時之後,事務管理器無法接收到所有參與者的反饋響應,那麼中斷事務,傳送回滾請求,事務管理器向所有參與者節點傳送 RollBack 請求,參與者接收到 RollBack 請求後,會利用在階段一記錄的Undo資訊執行事務的回滾操作,在完成回滾之後釋放事務執行期間佔用的資源,參與者在完成事務回滾之後,向協調者傳送ACK訊息,事務管理器在接受到所有參與者反饋的ACK訊息之後,完成事務中斷。

三階段提交(3PC)

3PC 主要是為了解決兩階段提交協定的單點故障問題和縮小參與者阻塞範圍。 是二階段提交(2PC)的改進版本,引入參與節點的超時機制之外,3PC把2PC的準備階段分成事務詢問(該階段不會阻塞)和事務預提交,則三個階段分別為 CanCommit、PreCommit、DoCommit

CanCommit 詢問狀態

CanCommit階段 協調者(Coordinator)會向參與者(Participant) 傳送CanCommit訊息,詢問是否可以執行操作,參與者收到訊息後,表示能夠執行,會返回給協調者能夠執行的(yes)命令

如果參與者不能執行,會返回No命令,釋放資源,結束事務。

PreCommit 預提交

PreCommit 階段如果協調者收到參與者返回的狀態值為YES,那麼就證明它們都有能力去執行這個操作,那麼協調者就會向所有參與者 傳送 PreCommit 訊息,協調者收到 PreCommit訊息後,回去執行本地事務,如果執行成功會將本地事務儲存到 undo和redo 後,再返回給協調者YES指令,如果執行本地事務失敗,返回協調者No,只要協調者收到一個執行失敗,給所有參與者傳送中斷事務訊息,參與者收到訊息後,對事務進行回滾操作。

在這個階段參與者和協調者都引入了超時機制,如果參與者沒有收到,協調者的訊息,或者協調者沒有收到參與者返回的預執行結果狀態,在等待超時之後,事務會中斷,避免了事務的阻塞。

協調者向參與者傳送PreCommit,如果參與者執行成功,返回yes

如果參與者執行失敗,只有有一個返回No到協調者,協調者會向參與者傳送中斷事務的訊息,參與者回滾事務。

DoCommit 提交

協調者收到所有參與者返回的狀態都是YES,這時協調者會向所有的參與者都傳送 DoCommit ,參與者收到 DoCommit 後,會真正的提交事務,當事務提交成功後,返回協調者YES狀態,表示我已經完成事務的提交了,協調者收到所有參與者都返回YES狀態後,那麼就完成了本次事務。

如果某個參與者返回No訊息,協調者傳送中斷事務訊息(abort),給參與者們,參與者回滾事務

3PC是2PC的升級版,引入了超時機制,解決了單點故障引起的事務阻塞問題,但是3PC依然不能解決事務一致性的問題,因為在DoCommit階段,如果由於網路或者超時等原則導致參與者收不到協調者傳送過來的 中斷事務訊息(abort) ,過了這個時間後,參與者會提交事務,本來是應該進行回滾,提交事務後,會導致資料不一致的問題出現,2PC雖然在網路故障情況下存在強一致性被破壞的問題,但是故障恢復以後能保證最終一致性,3PC雖然有超時時間,解決了阻塞,提高了可用性,但是犧牲了一致性,如果針對網路波動問題導致資料問題這一點上,2PC是優於3PC的

Seata

官網:https://seata.io/zh-cn/docs/overview/what-is-seata.html

Seata 是一款開源的分散式事務解決方案,致力於提供高效能和簡單易用的分散式事務服務。Seata 將為使用者提供了 AT、TCC、SAGA 和 XA 事務模式,為使用者打造一站式的分散式解決方案。

在微服務系統中,一般業務會被拆分成獨立的模組,在官方提供的結構圖中,我們可以看到當前主要分為三個模組.

  • 庫存服務: 對於商品庫存資訊進行增加或者減少操作
  • 訂單服務:根據使用者指定商品生成訂單
  • 賬戶服務: 從使用者賬戶中扣除餘額,增加積分,維護地址資訊等等

在當前架構中,使用者挑選心儀的商品下單後,需要三個服務來完成操作,每一個服務的內部都擁有一個獨立的本地事務來保證當前服務資料的強一致性,但是三個服務組成的全域性事務一致性就沒辦法進行保證,那麼Seata就是來解決這個問題的。

Seata術語

官網地址:https://seata.io/zh-cn/docs/overview/terminology.html

在瞭解Seata之前,我們先來了解一下 Seata 幾個關鍵的概念:

  1. TC(Transaction Coordinator)事務協調者:
    維護全域性和分支事務的狀態,驅動全域性事務提交或者回滾

  2. TM(Transaction Manager) 事務管理者: 發起者,同時一個RM的一種,定義全域性事務的範圍,開始全域性事務,提交或回滾全域性事務。

  3. RM(Resource Manager) 資源管理器: 參與事務的微服務,管理分支事務處理的資源,與TC交談以註冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾

Seata 2PC

一階段: 業務資料和回滾紀錄檔記錄在同一個本地事務中提交,釋放本地鎖和連線資源。

二階段: 提交非同步化,非常快速地完成。回滾通過一階段的回滾紀錄檔進行反向補償。

一階段本地事務提交前,需要確保先拿到 全域性鎖 。拿不到全域性鎖 ,不能提交本地事務。
拿全域性鎖的嘗試被限制在一定範圍內,超出範圍將放棄,並回滾本地事務,釋放本地鎖。

在資料庫本地事務隔離級別讀已提交或以上的基礎上,Seata(AT 模式)的預設全域性隔離級別是 讀未提交

如果應用在特定場景下,必需要求全域性的 讀已提交 ,目前 Seata 的方式是通過 SELECT FOR UPDATE 語句的代理。

Seata執行流程分析:

每個RM 使用 DataSourceProxy 連結資料路,目的是使用 ConnectionProxy ,使用資料來源和資料代理的目的是在第一階段將 undo和業務資料放在一個本地事務中提交,這樣就儲存了只要有業務操作就一定會有dudo紀錄檔,

在第一階段中,undo存放了資料修改前後修改的值,是為了事務回滾做好準備,在第一階段完成就已經將分支事務提交了,也就釋放了鎖資源。

TM開啟全域性事務開始,將XID全域性事務ID放在事務上下文中,通過feign呼叫將XID傳入下游伺服器中,每個分支事務將自己的 Branch ID分支事務ID和XID進行關聯,

在第二階段全域性事務提交,TC會通知各個分支參與者提交分支事務,在第一階段已經提交了分支事務,在這裡各參與者只需要刪除undo即可,並且可以非同步執行。

如果某一個分支事務異常了,第二階段全域性事務回滾操作,TC會通知各個分支參與者回滾分支事務,通過XID和Branch-ID找到對應的回滾紀錄檔,通過回滾紀錄檔生成的反向SQL執行,完成分支事務回滾到之前的狀態。

Seata 下載安裝

下載地址:https://github.com/seata/seata/releases

解壓後找到conf目錄

我們在啟動seata之前,首先要啟動nacos,其實也很簡單,只需要下載nacos後啟動就行,不知道nacos怎麼操作的看這裡的介紹nacos基礎介紹,啟動好之後,我們再來啟動seata,bin目錄下seata-server.bat

如果我們看到8091埠在監聽,並且在nacos看到服務註冊上去了,就表示我們seata啟動成功了

總結

到這裡我們關於分散式事務的和seata的介紹就講完了,其實關於分散式還有MQ實現可靠訊息最終一致性,MQ主要解決了兩個功能:本地事務與訊息傳送的原子性問題。事務參與方接收訊息的可靠性,下一篇會講解關於seata中AT、TCC、SAGA 和 XA 模式的介紹,感興趣的小夥伴歡迎在下方留言,點贊過百,就是通宵也出下篇。

我是牧小農,怕什麼真理無窮,進一步有進一步的歡喜大家加油!