面試90%都會翻車的高并發(fā)分布式事務(wù),我勸你好好啃透!

本地事務(wù)

事務(wù)Transaction由一組SQL組成,具有四個ACID特性

ACID

Atomicity 原子性 構(gòu)成事務(wù)的一組SQL,要么全部生效,要么全不生效,不會出現(xiàn)部分生效的情況

Consistency 一致性 數(shù)據(jù)庫經(jīng)過事務(wù)操作后從一種狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€狀態(tài)??梢哉f原子性是從行為上描述,而一致性是從結(jié)果上描述

isolation 隔離性 事務(wù)操作的數(shù)據(jù)對象 相對于 其他事務(wù)操作的數(shù)據(jù)對象相互隔離,互不影響

durability 持久性 事務(wù)提交后,其結(jié)果就是永久性的,即使發(fā)生宕機(非磁盤損壞)

事務(wù)實現(xiàn)

對于MySQL數(shù)據(jù)庫(InnoDB存儲引擎)而言,隔離性是通過不同粒度的鎖機制來實現(xiàn)事務(wù)間的隔離;原子性、一致性和持久性通過redo log 重做日志和undo log回滾日志來保證的。

redo log 當數(shù)據(jù)庫對數(shù)據(jù)做修改的時候,需要把數(shù)據(jù)頁從磁盤讀到buffer pool中,然后在buffer pool中進行修改,那么這個時候buffer pool中的數(shù)據(jù)頁就與磁盤上的數(shù)據(jù)頁內(nèi)容不一致,稱buffer pool的數(shù)據(jù)頁為dirty page 臟數(shù)據(jù),如果這個時候發(fā)生非正常的DB服務(wù)重啟,那么這些數(shù)據(jù)還沒在內(nèi)存,并沒有同步到磁盤文件中(注意,同步到磁盤文件是個隨機IO),也就是會發(fā)生數(shù)據(jù)丟失,如果這個時候,能夠在有一個文件,當buffer pool 中的data page變更結(jié)束后,把相應(yīng)修改記錄記錄到這個文件(注意,記錄日志是順序IO),那么當DB服務(wù)發(fā)生crash的情況,恢復DB的時候,也可以根據(jù)這個文件的記錄內(nèi)容,重新應(yīng)用到磁盤文件,數(shù)據(jù)保持一致。

undo log undo日志用于存放數(shù)據(jù)被修改前的值,如果修改出現(xiàn)異常,可以使用undo日志來實現(xiàn)回滾操作,保證事務(wù)的一致性。另外InnoDB MVCC事務(wù)特性也是基于undo日志實現(xiàn)的。undo日志分為insert undo log (insert語句產(chǎn)生的日志,事務(wù)提交后直接刪除)和 update undo log(delete和update語句產(chǎn)生的日志,由于該undo log可能提供MVVC機制使用,所以不能再事務(wù)提交時刪除)。

問題引入

CAP理論

image.png

CAP原則又稱CAP定理,指的是在一個分布式系統(tǒng)中,一致性(Consistency)、可用性(Availability)、分區(qū)容錯性(Partition tolerance)。CAP 原則指的是,這三個要素最多只能同時實現(xiàn)兩點,不可能三者兼顧。但由于在分布式系統(tǒng)中,分區(qū)容錯性必然存在,所以只能在一致性和可用性妥協(xié)。

傳統(tǒng)的DBMS,如MySQL其實CA組合,在主從架構(gòu)下,讀寫分離的情況下,是犧牲一定的一致性的(主從延遲)。

Base理論

base available 基本可用 分布式系統(tǒng)在出現(xiàn)故障時,允許損失部分可用功能,保證核心功能可用

soft state 軟狀態(tài) 允許系統(tǒng)中存在中間狀態(tài),這個狀態(tài)不影響系統(tǒng)可用性

eventually consistent 最終一致性 系統(tǒng)的中間狀態(tài)經(jīng)過短暫的時間后到達一致狀態(tài)

如何解決

場景舉例

考慮這樣一種業(yè)務(wù)場景,系統(tǒng)A調(diào)用系統(tǒng)B的退款服務(wù)進行退款,系統(tǒng)A更改內(nèi)部退款狀態(tài),接著調(diào)用系統(tǒng)C的短信服務(wù)通知用戶。

在這樣的一個場景下,由于網(wǎng)絡(luò)不可靠的必然存在,存在A、B、C三個系統(tǒng)之間一致性的問題。

本地表

針對上述場景,設(shè)計兩張表 退款記錄表短信發(fā)送記錄表 以及 相應(yīng)的補償Job

具體實現(xiàn)過程:

  1. 新增退款記錄表,狀態(tài)為處理中
  2. 調(diào)用系統(tǒng)B的退款服務(wù)進行退款
  3. 更新退款記錄狀態(tài)為對應(yīng)的狀態(tài)(成功/失敗)
  4. 如果退款成功,則新增短信發(fā)送記錄,記錄狀態(tài)為待發(fā)送
  5. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信
  6. 更新短信發(fā)送記錄為已發(fā)送

退款補償Job 查詢退款記錄表中處理中的記錄,調(diào)用系統(tǒng)B的退款服務(wù) 退款成功處理:

  1. 新增短信發(fā)送記錄,記錄狀態(tài)為待發(fā)送
  2. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信
  3. 更新短信發(fā)送記錄為已發(fā)送

短信通知補償Job 查詢短信發(fā)送記錄中待發(fā)送的記錄,調(diào)用系統(tǒng)C的短信服務(wù)

  1. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信
  2. 更新短信發(fā)送記錄為已發(fā)送

注意:

  • 系統(tǒng)B和系統(tǒng)C需要根據(jù)調(diào)用方傳的uuid支持冪等
  • 系統(tǒng)A、B、C會出現(xiàn)短暫的不一致,但最終一致

事務(wù)消息

可以將其視為兩階段提交消息實現(xiàn),以確保分布式系統(tǒng)中的最終一致性。事務(wù)性消息可確保本地事務(wù)的執(zhí)行和消息的發(fā)送可以原子方式執(zhí)行。

但是由于事務(wù)消息異步的特性,調(diào)用方拿不到消費方的處理結(jié)果,適用于不關(guān)心對方的返回結(jié)果/對方負責保證處理成功

image.png

針對上述場景,增加兩個事務(wù)消息的方式解決一致性問題,系統(tǒng)A通過發(fā)送事務(wù)消息的方式與系統(tǒng)B和系統(tǒng)C進行交互

具體實現(xiàn)過程:

  • 發(fā)送退款的事務(wù)消息
  • 新增退款記錄,狀態(tài)為:處理中
  • Commit退款事務(wù)消息

提供MQ事務(wù)callback

退款callback查詢

  • 有退款記錄且為處理中則Commit
  • 其他則Rollback

發(fā)送短信callback查詢

  • 有退款記錄且成功則Commit
  • 其他則Rollback

退款同步Job

查詢退款記錄表中處理中的記錄,調(diào)用系統(tǒng)B的退款查詢接口 同步狀態(tài) 其中退款成功處理:

  • 發(fā)送短信的事務(wù)消息
  • 更新退款記錄為成功
  • Commit短信事務(wù)消息

相關(guān)理論

二階段提交

image.png
image.png

二階段提交是解決分布式事務(wù)問題的重要理論基礎(chǔ),但也存在著明顯的問題:

  • 阻塞問題,參與者將協(xié)議消息發(fā)送給協(xié)調(diào)器后,它將阻塞直到收到提交或回滾,只能依賴協(xié)調(diào)者的超時機制
  • 協(xié)調(diào)者單點問題,如果協(xié)調(diào)者出現(xiàn)故障,則某些參與者將一直無法收到提交或回滾的消息。

為了解決二階段提交出現(xiàn)的問題,又有了三階段提交(Three-phase commit)

  • 解決阻塞問題:將2PC中的第一階段一分為二,提供了一個CanCommit階段,此階段并不鎖定資源,這樣可以大幅降低了阻塞概率
  • 解決單點問題:在參與者這邊也引入了超時機制

DTP Model

X / Open分布式事務(wù)處理DTP(Distributed Transaction Processing)模型是一種軟件體系架構(gòu),已經(jīng)成為事實上的事務(wù)模型組件的行為標準。它允許多個應(yīng)用程序共享由多個資源管理器提供的資源,并允許其工作被協(xié)調(diào)為全局事務(wù)。

image.png

ApplicationProgram(AP) 應(yīng)用程序定義了事務(wù)邊界并指定構(gòu)成事務(wù)的操作

ResourceManager(RM) 資源管理器用來管理我們需要訪問的共享資源,我們可以將它理解為關(guān)系數(shù)據(jù)庫、文件存儲系統(tǒng)、消息隊列、打印機等

TransactionManagger(TM) 事務(wù)管理器是一個獨立的組件,他為事務(wù)分配標識符并監(jiān)視事務(wù)的執(zhí)行情況,負責事務(wù)完成和故障恢復

CommunicationResourceManager(CRM) 通信資源管理器控制一個或多個 TM domain 之間分布式應(yīng)用的通信。

XA Specification

XA規(guī)范是X/Open關(guān)于分布式事務(wù)處理 (DTP)的規(guī)范。規(guī)范描述了全局的事務(wù)管理器與局部的資源管理器之間的接口。XA規(guī)范的目的是允許多個資源(如數(shù)據(jù)庫,應(yīng)用服務(wù)器,消息隊列,等等)在同一事務(wù)中訪問,這樣可以使ACID屬性跨越應(yīng)用程序而保持有效。XA使用兩階段提交來保證所有資源同時提交或回滾任何特定的事務(wù)。

XA規(guī)范描述了資源管理器要支持事務(wù)性訪問所必需做的事情。

image.png

TCC

image.png
image.png

saga

image.png

在 Saga 模式下,分布式事務(wù)內(nèi)有多個參與者,每一個參與者都是一個沖正補償服務(wù),需要用戶根據(jù)業(yè)務(wù)場景實現(xiàn)其正向操作和逆向回滾操作。

分布式事務(wù)執(zhí)行過程中,依次執(zhí)行各參與者的正向操作,如果所有正向操作均執(zhí)行成功,那么分布式事務(wù)提交。如果任何一個正向操作執(zhí)行失敗,那么分布式事務(wù)會去退回去執(zhí)行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務(wù)回到初始狀態(tài)。

image.png

Saga 模式下分布式事務(wù)通常是由事件驅(qū)動的,各個參與者之間是異步執(zhí)行的,Saga 模式是一種長事務(wù)解決方案。

Saga模式的優(yōu)勢是:

  • 一階段提交本地數(shù)據(jù)庫事務(wù),無鎖,高性能;
  • 參與者可以采用事務(wù)驅(qū)動異步執(zhí)行,高吞吐;
  • 補償服務(wù)即正向服務(wù)的“反向”,易于理解,易于實現(xiàn);

缺點:

  • Saga 模式由于一階段已經(jīng)提交本地數(shù)據(jù)庫事務(wù),且沒有進行“預留”動作,所以不能保證隔離性。

開源項目

seata

Seata 是一款開源的分布式事務(wù)解決方案,致力于在微服務(wù)架構(gòu)下提供高性能和簡單易用的分布式事務(wù)服務(wù)。支持AT、TCC、SAGA、XA四種模式,對微服務(wù)框架支持友好。

image.png

如下圖所示,Seata 中有三大模塊,分別是 TM、RM 和 TC。 其中 TM 和 RM 是作為 Seata 的客戶端與業(yè)務(wù)系統(tǒng)集成在一起,TC 作為 Seata 的服務(wù)端獨立部署。

TC - 事務(wù)協(xié)調(diào)者 維護全局和分支事務(wù)的狀態(tài),驅(qū)動全局事務(wù)提交或回滾。

TM - 事務(wù)管理器 定義全局事務(wù)的范圍:開始全局事務(wù)、提交或回滾全局事務(wù)。

RM - 資源管理器 管理分支事務(wù)處理的資源,與TC交談以注冊分支事務(wù)和報告分支事務(wù)的狀態(tài),并驅(qū)動分支事務(wù)提交或回滾。

在 Seata 中,分布式事務(wù)的執(zhí)行流程:

  • TM 開啟分布式事務(wù)(TM 向 TC 注冊全局事務(wù)記錄);
  • 按業(yè)務(wù)場景,編排數(shù)據(jù)庫、服務(wù)等事務(wù)內(nèi)資源(RM 向 TC 匯報資源準備狀態(tài) );
  • TM 結(jié)束分布式事務(wù),事務(wù)一階段結(jié)束(TM 通知 TC 提交/回滾分布式事務(wù));
  • TC 匯總事務(wù)信息,決定分布式事務(wù)是提交還是回滾;
  • TC 通知所有 RM 提交/回滾 資源,事務(wù)二階段結(jié)束;

AT模式

AT 模式是一種無侵入的分布式事務(wù)解決方案。在 AT 模式下,用戶只需關(guān)注自己的“業(yè)務(wù) SQL”,用戶的 “業(yè)務(wù) SQL” 作為一階段,Seata 框架會自動生成事務(wù)的二階段提交和回滾操作。

一階段:業(yè)務(wù)數(shù)據(jù)和回滾日志記錄在同一個本地事務(wù)中提交,釋放本地鎖和連接資源。 二階段:提交異步化,非??焖俚赝瓿??;貪L通過一階段的回滾日志進行反向補償。

image.png

在一階段,Seata 會攔截“業(yè)務(wù) SQL”,首先解析 SQL 語義,找到“業(yè)務(wù) SQL”要更新的業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)被更新前,將其保存成“before image”,然后執(zhí)行“業(yè)務(wù) SQL”更新業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)更新之后,再將其保存成“after image”,最后生成行鎖。以上操作全部在一個數(shù)據(jù)庫事務(wù)內(nèi)完成,這樣保證了一階段操作的原子性。

image.png

TCC模式

image.png

一個分布式的全局事務(wù),整體是 兩階段提交 的模型。全局事務(wù)是由若干分支事務(wù)組成的,分支事務(wù)要滿足 兩階段提交 的模型要求,即需要每個分支事務(wù)都具備自己的:

一階段 prepare 行為 二階段 commit 或 rollback 行為

TCC 模式,不依賴于底層數(shù)據(jù)資源的事務(wù)支持:

  • 一階段 prepare 行為:調(diào)用 自定義 的 prepare 邏輯。
  • 二階段 commit 行為:調(diào)用 自定義 的 commit 邏輯。
  • 二階段 rollback 行為:調(diào)用 自定義 的 rollback 邏輯。

所謂 TCC 模式,是指支持把 自定義 的分支事務(wù)納入到全局事務(wù)的管理中。

Saga模式

目前SEATA提供的Saga模式是基于狀態(tài)機引擎來實現(xiàn)的,機制是:

  1. 通過狀態(tài)圖來定義服務(wù)調(diào)用的流程并生成 json 狀態(tài)語言定義文件
  2. 狀態(tài)圖中一個節(jié)點可以是調(diào)用一個服務(wù),節(jié)點可以配置它的補償節(jié)點
  3. 狀態(tài)圖 json 由狀態(tài)機引擎驅(qū)動執(zhí)行,當出現(xiàn)異常時狀態(tài)引擎反向執(zhí)行已成功節(jié)點對應(yīng)的補償節(jié)點將事務(wù)回滾 (異常發(fā)生時是否進行補償也可由用戶自定義決定)
  4. 可以實現(xiàn)服務(wù)編排需求,支持單項選擇、并發(fā)、子流程、參數(shù)轉(zhuǎn)換、參數(shù)映射、服務(wù)執(zhí)行狀態(tài)判斷、異常捕獲等功能

狀態(tài)機引擎原理

image.png
  • 圖中的狀態(tài)圖是先執(zhí)行stateA, 再執(zhí)行stateB,然后執(zhí)行stateC
  • "狀態(tài)"的執(zhí)行是基于事件驅(qū)動的模型,stateA執(zhí)行完成后,會產(chǎn)生路由消息放入EventQueue,事件消費端從EventQueue取出消息,執(zhí)行stateB
  • 在整個狀態(tài)機啟動時會調(diào)用Seata Server開啟分布式事務(wù),并生產(chǎn)xid, 然后記錄"狀態(tài)機實例"啟動事件到本地數(shù)據(jù)庫
  • 當執(zhí)行到一個"狀態(tài)"時會調(diào)用Seata Server注冊分支事務(wù),并生產(chǎn)branchId, 然后記錄"狀態(tài)實例"開始執(zhí)行事件到本地數(shù)據(jù)庫
  • 當一個"狀態(tài)"執(zhí)行完成后會記錄"狀態(tài)實例"執(zhí)行結(jié)束事件到本地數(shù)據(jù)庫, 然后調(diào)用Seata Server上報分支事務(wù)的狀態(tài)
  • 當整個狀態(tài)機執(zhí)行完成, 會記錄"狀態(tài)機實例"執(zhí)行完成事件到本地數(shù)據(jù)庫, 然后調(diào)用Seata Server提交或回滾分布式事務(wù)

最后

關(guān)注公眾號:程序員白楠楠, 領(lǐng)取2020最新Java面試題手冊(200多頁PDF文檔)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容