ACID-本地事務-分佈式事務

​學習思路

  1. ACID解釋

  2. 本地事務

  3. 分佈式事務解決方案及優缺點

  4. 生產最常用的方案

 

一、ACID-本地事務

學習事務的前提就是要了解什麼是ACID(事務的四大特性)

  1. Atomicity(原子性):一個事務的執行過程就是一個原子操作,要麼全部成功,要麼全部失敗,不會出現其它情況

  2. Consistency(一致性):數據執行前後,數據的完整性必須是一致的,比如轉賬A+1;B-1但總數還是不變的

  3. Isolation(隔離性):多個用戶併發執行事務,每個事務是相互隔離的,不會產生任何影響

  4. Durability(持久性):事務一旦提交,數據便永久的存儲在了數據庫,不受外界條件影響

只用滿足了以上4大特性纔算一個完整的事務

 

二、本地事務

系統發展初期,單體應用對應一個數據庫,本地操作數據我們很容易就實現了ACID,主要流程:開啓事務-->操作數據 -->提交/回滾事務;實際使用中主要有:編程式事務、聲明式事務

  1. 編程式事務:主要通過代碼編寫自己手動實現,開發一般不用

  2. 聲明式事務:主要通過使用AOP攔截方法在方法執行前後分別開始事務,提交/回滾事務;實際使用主要通過配置文件配置或者@Transaction註解實現

三、分佈式事務解決方案及優缺點

隨着系統拆分到數據庫拆分,我們的一個操作需要跨多個系統跨多個數據庫才能完成,然而多個數據庫協同操作也就保證不了ACID四大特性

爲了解決問題XA協議來了

1、XA協議:

        由之前的Application控制一個ResourceManager變成了:一個TransactionManager管理多個本地ResourceManager協同完成一次事務

基於XA協議從而產出了後面的兩階段提交和三階段提交

 

2、兩階段提交(2pc)

  1. TM(事務管理器)分別向多個RM(本地資源管理器)發送準備提交指令(如果此時一方發送失敗,表示該事務失敗);RM執行完本地業務後分別響應TM(如果此時一方返回NO或者異常表示事務失敗)

  2. 如果RM返回成功;TM分別向RM發送提交指令;如果RM返回失敗;TM分別向RM發送回滾指令

缺點:

  1. 如果在準備階段如果其中一個RM掛掉了,其它RM就不應該走,而不是回滾

  2. TM單點問題:如果TM掛掉會導致整個服務不可用

  3. 同步阻塞問題:準備階段需要等待所有準備結果,如果其中一步沒有返回結果將會一直阻塞等待

  4. 數據不一致問題:如果發送1個RM後TM掛掉將會導致其它RM跟這個數據不一致

 

3、三階段提交(3pc)

針對兩階段的缺點產生了三階段

  1. TM向RM發送真正的準備請求時先發送can_commit請求驗證RM是否正常(如果有RM異常直接返回事務失敗)

  2. 如果全部正常:TM向RM發送pre_commit(準備)請求,RM執行操作返回操作結果

  3. 如果第二步返回成功:TM向RM發送提交通知;如果返回失敗發送回滾通知

缺點:

  1. TM單點問題

  2. 如果在最後一步TM發送的是回滾通知,但其中有部分RM沒有接受到指令那麼會超時提交,出現數據不一致的情況

 

2pc和3pc的對比

  1. can_commit

    1. 2pc:直接進入準備階段執行業務,如果有RM宕機還要回滾其它的

    2. 3pc新增can_commit操作驗證RM是否正常

  2. 同步阻塞:

    1. 2pc在準備過程中如果其中一個RM阻塞,其它RM都要處於阻塞等待中

    2. 3pc中新增的超時機制,防止無限阻塞

  3. 自動提交機制:

    1. 2pc:TM發送RM提交或回滾無響應會進入阻塞

    2. 3pc:如果RM沒有接受到TM的任何提交或回滾請求,超時後自動提交(大部分機率超時的請求基本上都是成功)

 

面對2pc和3pc的這麼多缺點,所有實際開發中這兩種基本不用

 

4、TCC機制

解釋:

  1. 主業務數據庫向下遊業務庫發送Try操作(直接執行本地事務,但數據狀態不是終態,而是一箇中間狀態(比如凍結))

  2. 當所有從業務庫返回成功後,主業務發送confirm請求,從業務執行confirm方法(將中間狀態改爲最終成功狀態)

  3. 當部分返回失敗後:主業務發送cancel請求,從業務執行cancel方法(將中間狀態改爲失敗,恢復Try操作之前的狀態)

優點:

  1. 各個子系統自己控制事務,不存在事務阻塞等待問題

  2. 各個系統都是集羣部署,不存在單點問題

  3. 一致性得到保障

缺點:

  1. 各個系統需要實現try、confirm、cancel的相關邏輯,代碼侵入性高

  2. 如果confirm或者cancel執行失敗需要定時任務實現最終一致

題外話:此種方法有沒有感覺很熟悉,我們實際開發中其實不自覺的會用到一些大同小異的補償機制,思想都一樣

 

5、基於MQ實現最終一致性

聽起來很高大尚,實現很簡單、、、

我們這裏最好使用支持事務消息的MQ比如RocketMQ,不支持事務的MQ實現略顯麻煩,但原理一樣(基於RocketMQ的點擊:RocketMQ事務消息學習

我們這裏主要學習一下不支持事務的MQ

不管支不支持事務,我們要實現的主要思路:

  1. 使發送MQ消息和執行本地事務兩個操作放入一個原子操作(放入一個事務)

  2. 消費失敗的消息,利用MQ的重試機制或者記錄消息數據利用定時任務重試消費,到達最終一致性

第一步你可能會疑問:我將發送MQ消息和放入本地事務就可以了;這樣大部分情況沒問題,但發送MQ是遠程調用如果網絡異常發生超時會產生大量的長事務,拖垮系統

研發思路:

  1. 新建發送消息表(記錄發送的消息)

  2. 不直接對接MQ發送消息,而是將消息入庫,把消息入庫和本地業務放入一個本地事務,確保本地業務和消息同時成功

  3. 定時任務掃發送消息庫,發送消息,發送成功刪除消息(可批量查詢)

  4. 新建消費消息表(記錄發送到消費者消息)

  5. 當MQ重試到一定次數之後可利用MQ的死信隊列或者將消息存入消費消息表(一般這種長時間錯誤都是數據異常,可配合報警人工介入)

  6. 定時任務掃表消費消息,消費成功刪除消息(可批量查詢)

注意:所有的MQ消費接口,存入表操作一定要做冪等

 

四、生產最常用的方案

  1. 狀態類業務可按狀態機實現狀態控制用TCC思想+定時任務做補償

  2. 通知類業務、耗時比較長的新增業務,可引入MQ,可解耦、緩衝峯值、做最終一致

  3. 但很多情況下我們都不用事務、、、90%的重點業務、容易出錯的業務通過定時任務做補償就能解決:補償一定次數我們報警人工介入

公衆號主要記錄各種源碼、面試題、微服務技術棧,幫忙關注一波,非常感謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章