分佈式事務
事務
事務遵循原則ACID(原子性,一致性,隔離性,持久性),一個事務中對數據庫的多次sql操作要麼都成功commit,要麼都失敗rollback,且多個事務之間不會產生影響,在一個事務結束之後數據落地數據庫,以後也可以查到
分佈式事務的由來
在當今分佈式架構下,不同的服務都會有屬於自己的數據庫,在一個服務中對一個數據庫進行操作我們可以使用數據庫自帶的事務來處理,但是多個服務,多個數據庫就沒有辦法使用數據庫自帶的事務來控制多個數據庫.
分佈式事務最大的問題
CAP原則我們無法同時滿足一致性(強一致性)C/可用性A/分區容錯性P,那麼我們只能進行捨去,因爲是不同服務之間的事務,在不同服務之間進行通信的時候會出現一些不可預料的問題,所有我們無法百分百保證事務,但是我們要做到N個9(99.9999…%)
解決方式
-
TCC
-
阿里RocketMQ
-
seata
這裏我們主要說這三種
場景
下單操作,訂單需要調用庫存,積分等服務
- 訂單添加成功(order_Server)
- 庫存扣件成功(stock_Server)
- 積分添加成功(integral_Server)
- 都成功或都失敗
TCC解決
-
觸發操作在訂單系統中
-
添加訂單
-
訂單嘗試扣件庫存try(RPC內部調用接口)
-
訂單嘗試添加積分try(RPC內部調用接口)
-
都沒有問題
-
訂單確認扣減庫存confirm(RPC內部調用接口)
-
訂單確認添加積分confirm(RPC內部調用接口)
-
當這之中出現的問題
-
訂單取消扣減庫存cancel(RPC內部調用接口)
-
訂單取消添加積分cancel(RPC內部調用接口)
這樣我們就保持了要麼都成功要麼都失敗
現成的框架有tcc-transaction/Hmily/ByteTCC/EasyTransaction等
缺點:
業務侵入性較強,每一個接口都需要實現try/cinfirm/cancel三個接口
阿里消息隊列(RocketMQ)
-
開啓本地事務添加訂單
-
訂單發送扣減庫存的事務消息到消息隊列中
-
訂單發送添加積分的事務消息到消息隊列中
-
此時的消息是無法被消費的處於阻塞狀態
-
提交事務
-
確認事務消息讓消息可以被消費
-
當事務消息長期處於阻塞狀態的時候
-
消息隊列會訪問消息的生產者,詢問消息是否可以被消費了
-
得到確認後消費者消費消息
-
消費失敗會有重試機制
-
當消息超過重試機制後發送預警郵件人工干預
缺點:消息隊列是異步執行的當數據庫使用樂觀鎖控制時,數據其他線程修改之後就無法再次修改(根據業務場景靈活判斷),這時失敗就會很常見(由於消息隊列時按順序執行的只有消費者會修改這個數據就不會出現這個問題)
阿里開源組件seata(主要)
概念
- TC 事務協調者(seataServer)
- TM 事務發起者(orderServer)
- RM 事務參與者(stockServer/IntegralServer)
流程(AT模式)
-
啓動事務管理者
-
啓動事務發起者和參與者
-
將事務發起者和參與者註冊到協調者中去
-
訂單發起事務
-
事務協調者會生成一個XID 總事務id(假設 12138 )
-
訂單扣減庫存
-
庫存(參與者)生成自己的一個事務ID(123),將自己的事務ID添加到總事務組中
-
總事務12138下就會有一個branch_id 123
-
訂單添加積分
-
積分(參與者)生成一個自己到事務ID(126),將自己的事務ID添加到總事務組中
-
總事務12138下就會有兩個的branch_id 123,126
-
當訂單提交事務就會告訴事務到協調者一起提交分支事務
-
如果者中間有某一段操作拋出異常
-
協調者會將總事務下的所有分支事務ID全部回滾
缺點:如果你的事務鏈過長,總事務下的分支事務id過多,那麼就是你這個業務同時對多個數據庫進行鎖資源,高併發情況下會出現嚴重阻塞