1. 事務基本概念
1.1 什麼是事務?
事務是恢復和併發控制的基本單位,事務有四個特性(ACID),原子性(Atomicity),一 致性(Consistency),隔離性(Isolation),持久性(Durability)。
1.2 事務經典場景
假設這樣一個場景:
A 給 B 轉賬 100,流程步驟如下:
1、A 減 100
2、B 多 100。
如果第一步驟執行後,系統崩潰掉了。會怎麼樣呢?
問題:A 被減掉了 100,但 B 的錢未能加 100. 此時,A + B 的金錢總額憑空少了 100。數據 不一致了。
解決思路呢?我們希望步驟 1 和步驟 2 能夠綁定在一起執行,不可分;並且在步驟 1 和步驟 2執行的過程中,儘量規避中間狀態。即謂事務。
1.3 事務原理與鎖
1.3.1 鎖的問題場景:
多對一問題,多個操作者同時操作一個資源,而資源的狀態變化是非原子的(有中間態), 哄搶會導致資源狀態混亂
1.3.2 事務的問題場景:
一對多的問題,一個操作者需要綁定操作一系列資源(比如多條 sql),若任何一條操作失敗,
都會導致整個操作失去意義;
1.3.3 事務的實現:
1. redo log
redo log 叫做重做日誌,是用來實現事務的持久性。
該日誌文件由兩部分組成:重做日誌緩衝(redo log buffer)以及重做日誌文件(redo log),前者是在內存中,後者在磁盤中。當事務提交之後會把所有修改信息都會存到該日誌中。
PS:mysql 爲了提升性能不會把每次的數據修改都實時同步到磁盤,而是會先存到 Boffer Pool(緩衝池)裏頭,把這個當作緩存 來用。然後使用後臺線程去做緩衝池和磁盤之間的同步。
redo log 主要用來恢復數據, 用於保障,已提交事務的持久化特性(宕機時,redo log 的信息是全的)
2.undo log
undo log 叫做回滾日誌,用於記錄數據被修改前的信息。他正好跟前面所說的重做日誌所記錄的相反,重做日誌記錄數據被修改後的信息。
undo log 主要記錄的是數據的邏輯變化,爲了在發生錯誤時回滾之前的操作,需要將之前的操作都記錄下來,然後在發生錯誤 時纔可以回滾。
PS:mysql 每次寫入數據或者修改數據之前都會把修改前的信息記錄到 undo log
undo log 是用來回滾數據,用於保障 未提交事務的原子性
3. mysql 鎖技術
當多個請求同時來臨時,mysql 要控制讀讀可並行,而寫讀,寫寫不能並行
4. MVCC 基礎
MVCC (MultiVersion Concurrency Control) 叫做多版本併發控制。
InnoDB 的 MVCC ,是通過在每行記錄的後面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存了 行的過期時間,當然存儲的並不是實際的時間值,而是系統版本號。他的主要實現思想是通過數據多版本來做到讀寫分離。從而實現不加鎖讀進而做到讀寫並行。
事務的原子性是通過 undo log 來實現的
事務的持久性是通過 redo log 來實現的
事務的隔離性是通過 (讀寫鎖+MVCC)來實現的
而事務的終極大 boss 一致性是通過原子性,持久性,隔離性來實現的!!!
1.4 事務的操作過程
1.編程式事務:使用 TransactionTemplate 或者直接使用底層的 TransactionManager 來操作事務 commit 或者rollback。
2.聲明式事務:建立在 AOP 基礎上,通過對方法前後進行攔截,加入編程式事務裏的流程控制邏輯。使用的時候只需要在方法前 面加上@Transactional 註解
2 分佈式事務
2.1 分佈式事務概念
2.1.1 分佈式事務產生的原因
隨着互聯網高速發展,事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位於不同的分佈式系統的不同節點 之上。簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分佈在不同的服務器上,且屬於不同的應用。在這種 環境中,我們之前說過數據庫的 ACID 四大特性,已經無法滿足我們分佈式事務。
2.1.2 CAP 理論
CAP 定理,又被叫作布魯爾定理。
CAP 指的是:一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance)。
CAP 定律說的是,在一個分佈式系統中,最多隻能滿足 C、A、P 中的兩個,不可能三個同時滿足。而在分佈式系統中,網絡無法 100% 可靠,分區其實是一個必然現象。
如果我們選擇了 CA 而放棄了 P,那麼當發生分區現象時,爲了保證一致性,這個時候必須拒絕請求,但是 A 又不允許,所以分佈式系統理論上 不可能選擇 CA 架構,只能選擇 CP 或者 AP 架構。
而且,顯然,任何橫向擴展策略都要依賴於數據分區。因此,設計人員必須在一致性與可用性之間做出選擇。
2.1.3 BASE 理論
Basically Available(基本可用) : 分佈式系統在出現故障時,允許損失部分可用功能,保證核心功能可用
往往在分佈式系統中無法實現完全一致性,於是有了 BASE 理論,它是對 CAP 定律的進一步擴充BASE 指的是:
-
Soft state(軟狀態) : 允許系統中存在中間狀態,這個狀態不影響系統可用性
-
Eventually consistent(最終一致性) : 經過一段時間後,所有節點數據都將會達到一致
BASE 理論是對 CAP 中的一致性和可用性進行一個權衡的結果
BASE 理論核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性
BASE 和 ACID 是相反的,它完全不同於 ACID 的強一致性模型,而是通過犧牲強一致性來獲得可用性,並允許數據在一段時 間內是不一致的,但最終達到一致狀態。
2.2 基於 XA 協議的兩階段提交
X/Open 組織提出了分佈式事務的規範 ----- XA 協議
XA 協議包含兩部分:事務管理器和本地資源管理器。其中本地資源管理器往往由數據庫實現,目前主流的關係型數據庫都實現了 XA 接口, 而事務管理器作爲全局的調度者,負責各個本地資源的提交和回滾。
XA 的核心,便是全局事務,通過 XA 二階段提交協議,與各分佈式數據交互,分準備與提交兩個階段 邏輯流程如下圖:
在 XA 協議中事務分爲兩階段:
事務管理器要求每個涉及到事務的數據庫預提交(precommit)此操作,並反映是否可以提交。 事務協調器要求每個數據庫提交數據,或者回滾數據。
優點:
儘量保證了數據的強一致,實現成本較低,在各大主流數據庫都有自己實現,對於 MySQL 是從 5.5 開始支持。
缺點:
1、單點問題:事務管理器在整個流程中扮演的角色很關鍵,如果其宕機,比如在第一階段已經完成,在第二階段正準備提交 的時候事務管理器宕機,資源管理器就會一直阻塞,導致數據庫無法使用。、
2、同步阻塞:在準備就緒之後,資源管理器中的資源一直處於阻塞,直到提交完成,釋放資源。
3、數據不一致:兩階段提交協議雖然爲分佈式數據強一致性所設計,但仍然存在數據不一致性的可能。
比如在第二階段中,假設協調者發出了事務 Commit 的通知,但是因爲網絡問題該通知僅被一部分參與者所收到並執行 了 Commit 操作,其餘的參與者則因爲沒有收到通知一直處於阻塞狀態,這時候就產生了數據的不一致性。
兩階段提交方案鎖定資源時間長,對性能影響很大,基本不適合解決微服務事務問題。
2.3 3PC事務
3PC,全稱 “three phase commit”,是 2PC 的改進版,其將 2PC 的 “提交事務請求” 過程一分爲二。
2.3.1第一個階段: CanCommit
1.事務詢問:協調者向所有的參與者發送一個包含事務內容的 canCommit 請求,詢問是否可以執行事務提交操作,並開始等待各參與者的響應。
2.各參與者向協調者反饋事務詢問的響應:參與者接收來自協調者的 canCommit 請求,如果參與者認爲自己可以順利執行事務,就返回 Yes,否則反饋 No 響應。
這一階段主要是確定分佈式事務的參與者是否具備了完成 commit 的條件,並不會執行事務操作。不鎖表
2.3.2 第二階段:precommit
協調者在得到所有參與者的響應之後,會根據結果執行 2 種操作:執行事務預提交,或者中斷事務。
1. 執行事務預提交分爲 3 個步驟:
-
發送預提交請求:協調者向所有參與者節點發出 preCommit 的請求,並進入 prepared 狀態。
-
事務預提交:參與者受到 preCommit 請求後,會執行事務操作,對應 2PC 中的 “執行事務”,也會 Undo 和Redo 信息記錄到事務日
志中。
-
各參與者向協調者反饋事務執行的結果:如果參與者成功執行了事務,就反饋 Ack 響應,同時等待指令:提交(commit) 或終止(abor)。
2. 中斷事務也分爲 2 個步驟:
-
發送中斷請求:協調者向所有參與者節點發出 abort 請求 。
-
中斷事務:參與者如果收到 abort 請求或者超時了,都會中斷事務。
2.3.3 第三階段:docommit
1. 執行提交
-
發送提交請求:進入這一階段,如果協調者正常工作,並且接收到了所有協調者的 Ack 響應,那麼協調者將從 “預提交” 狀態變爲 “提 交” 狀態,並向所有的參與者發送 doCommit 請求 。
-
事務提交:參與者收到 doCommit 請求後,會正式執行事務提交操作,並在完成之後釋放在整個事務執行期間佔用的事務資源。
-
反饋事務提交結果:參與者完成事務提交後,向協調者發送 Ack 消息。
-
完成事務:協調者接收到所有參與者反饋的 Ack 消息後,完成事務。
2. 中斷事務 (假設有任何參與者反饋了 no 響應,或者超時了,就中斷事務)。
-
發送中斷請求:協調者向所有的參與者節點發送 abort 請求。
-
事務回滾:參與者接收到 abort 請求後,會利用其在二階段記錄的 undo 信息來執行事務回滾操作,並在完成回滾之後釋放整個事務執行
期間佔用的資源。
-
反饋事務回滾結果:參與者在完成事務回滾之後,想協調者發送 Ack 消息。
-
中斷事務:協調者接收到所有的 Ack 消息後,中斷事務。
2.3.4 與 2pc 的區別
注意:在階段三,可能會出現 2 種故障:協調者出現問題/協調者和參與者之間的網絡故障一段出現了任一一種情況,最終都會導致參與者無法收到 doCommit 請求或者 abort 請求, 針對這種情況,參與者都會在等待超時之後,繼續進行事務提交。
優點:
相比較 2PC,最大的優點是減少了參與者的阻塞範圍(第一個階段是不阻塞的),
並且能夠在單點故障後繼續達成一致(2PC 在提交階段會出現此問題,而 3PC 會根據協調者的狀態進行回滾或者提交)。
缺點:
如果參與者收到了 preCommit 消息後,出現了網絡分區,那麼參與者等待超時後,都會進行事務的提交,這必然會出現事務不一致的問題
2.4 TCC方案
TCC 其實就是採用的補償機制,其核心思想是:針對每個操作,都要註冊一個與其業務邏輯對應的確認和補償(撤銷)操作。其將整個業務邏輯的每個分支顯式的分成了 Try、Confirm、Cancel 三個操作。Try 部分完成業務的準備工作,confirm 部分完成業務的提交,cancel
部分完成事務的回滾。
優點:跟 2PC 比起來,實現以及流程相對簡單了一些,但數據的一致性比 2PC 也要差一些
缺點: TCC 屬於應用層的一種補償方式,所以需要程序員在實現的時候多寫很多補償的代碼,而且補償的時候也有可能失敗,在一些場景中,一些 業務流程可能用 TCC 不太好定義及處理。
2.5 MQ(事務消息)
目前,僅阿里雲的 RocketMQ 支持事務消息。幫助用戶實現類似 X/Open XA 的分佈事務功能,通過 MQ 事務消息能達到分佈式事務的最終一致。
-
1、發送方向 MQ 服務端發送消息
-
2、MQ Server 將消息持久化成功之後,向發送方 ACK 確認消息已經發送成功,此時消息爲半消息
-
3、發送方開始執行本地事務邏輯
-
4、發送方根據本地事務執行結果向 MQ Server 提交二次確認(Commit 或是 Rollback),MQ Server 收到 Commit狀態則將半消息標記爲可投遞,訂閱方最終將收到該消息;MQ Server 收到 Rollback 狀態則刪除半消息,訂閱方將不會接受該消息
5、在斷網或者是應用重啓的特殊情況下,上述步驟 4 提交的二次確認最終未到達 MQ Server,經過固定時間後 MQ Server 將對該消息發起消息回查。
-
6、發送方收到消息回查後,需要檢查對應消息的本地事務執行的最終結果
-
7、發送方根據檢查得到的本地事務的最終狀態再次提交二次確認,MQ Server 仍按照步驟 4 對半消息進行操作
-
其中,事務消息發送對應步驟 1、2、3、4,事務消息回查對應步驟 5、6、7
-
2.6 Lcn事務
-
2.6.1 背景
-
LCN 名稱是由早期版本的 LCN 框架命名,在設計框架之初的 1.0 ~ 2.0 的版本時框架設計的步驟是如下,各取其首字母得來的 LCN 命名。
-
鎖定事務單元(lock) 確認事務模塊狀態(confirm)通知事務(notify)
-
2.6.2 框架定位
LCN 並不生產事務,LCN 只是本地事務的協調工 -
TX-LCN 定位於一款事務協調性框架,框架其本身並不操作事務,而是基於對事務的協調從而達到事務一致性的效果。
-
2.6.3 事務控制原理TX-LCN 由兩大模塊組成, TxClient、TxManager,
-
TxClient 作爲模塊的依賴框架,提供 TX-LCN 的標準支持,TxManager 作爲分佈式事務的控制方。事務發起方或者參與反都由TxClient 端來控制。
-
原理圖:
1.創建事務組
是指在事務發起方開始執行業務代碼之前先調用 TxManager 創建事務組對象,然後拿到事務標示 GroupId 的過程。
2.加入事務組
添加事務組是指參與方在執行完業務方法以後,將該模塊的事務信息通知給 TxManager 的操作。
3.通知事務組
是指在發起方執行完業務代碼以後,將發起方執行結果狀態通知給 TxManager,TxManager 將根據事務最終狀態和事務組的信息 來通知相應的參與模塊提交或回滾事務,並返回結果給事務發起方。
2.7 Seata事務
Seata(Simple Extensible Autonomous Transaction Architecture) 是 阿里巴巴開源的分佈式事務中間件,以高效並且對業 務 0 侵入的方式,解決微服務場景下面臨的分佈式事務問題。
2.7.2 設計思想
seata 的 AT 模式,採用的是大量運用在數據庫軟件的 Write Ahead Log 思想,即把事務的信息以事務日誌的方式記錄下來。這種處理方式,實際上是對傳統兩階段提交的一種改進和優化。主要有幾個關鍵點:
-
傳統兩階段提交協議是阻塞協議,性能差
-
傳統兩階段提交協議高可用性不好
-
傳統兩階段提交協議的全局事務隔離機制不支持
-
根據八二原則,80% 的涉及到全局事務的業務是能正常完成並提交的。
因此,在 AT 模式下,seata 採取的做法是,一個事務分支的數據庫操作執行完後,馬上進行本地事務的提交,從而釋放相關的數據庫 資源。
-
1、分支事務中數據的本地鎖由本地事務管理,在分支事務 Phase1 結束時釋放。
-
2、同時,隨着本地事務結束,連接 也得以釋放。
-
3、分支事務中數據的全局鎖在事務協調器側管理,在決議 Phase2 全局提交時,全局鎖馬上可以釋放。只有在決議全 局回滾的情況下,全局鎖才被持有至分支的 Phase2 結束。
2.7.3 本地事務執行流程
在進行本地提交的前提是,seata 會解析 SQL,獲取數據庫表的元數據,根絕 SQL 類型,選擇性地生成數據的前置鏡像和後置鏡像, 保存在 undo_log 表中,並且要求與保存 undo_log 與業務 SQL 在同一個本地事務內。
2.7.4 全局事務提交流程
因爲每個分支事務的本地事務都已經被提交,所以如果全局事務能夠順利進行到“提交“這一階段,那麼意味着所有事務分支的本地事 務都已經被提交了,數據的一致性已經得到了保證。
這個時候全局事務的提交就變得十分輕量級,就是把 undo_log 對應的記錄刪掉即可,即使是當時刪除失敗了,也已經不會影響全局事 務的最終結果,這次刪不了,那就待會再刪,程序刪不了,沒事,頂多人工刪。
2.7.5 全局事務回滾流程
如果全局事務的任何一個事務分支失敗了,那麼全局事務就進入“回滾“流程,回滾時依據先前保存好數據鏡像,將原來的數據回放回 去。
如果全局回放成功,那麼數據的一致性也就得到了保證,如果回放不成功,那麼事務就進入異常。應對異常,可能需要重試,可能需要 人工介入。