# 訊息佇列解決分散式事務
訊息佇列解決分散式事務
-
本地訊息表:通常處於同一張資料表,通過事務觸發器就能實現,但無法解決兩張表處於不同的資料庫問題
begin transaction: update User set account = account - 100 where userId = 'A' insert into message(userId,amount,status) values('A',100,1) commit transaction
-
分散式事務-兩階段提交訊息:
-
基本原理:通過TC事務協調器,分別去確認A,B,C事務的發生,全部成功則使用TC進行提交,否則的話則進行abort
-
缺點:涉及多次節點提交,通訊時間太長;鎖定的資源也變得更多。
-
-
分散式事務 - 業務方自己實現(使用訊息佇列來避免分散式事務),例子:B事務伴隨著A事務的發生
-
基本原理:將建立事務和釋出事務分成兩步操作,建立事務A會在本地資料庫存入訊息資料庫M進行記錄,而並不傳送訊息至B;
當A事務完成時,再將M傳送至B;
B中通過M_Apply表查詢這一訊息是否已經操作,未操作則觸發操作,或者拋棄;
B事務完成後,將訊息傳送至A,A再在庫裡面刪除M表;
即需要存在的表有:要執行的A表和B表,M表(儲存A的事務訊息發起,存在於A資料庫)和M_apply(校驗M訊息,存在於B資料庫)
//表M的存在是實現業務與訊息的耦合與解耦 begin transaction update A set amout=amount - 1000 where userid=1 insert into message(userid,amount,status) values (1,1000,1) end transaction commit; //表M_apply的存在解決訊息的重複提交 for each msg in queue begin transaction select count(*) as cnf from message_apply where msg_id=msg.msg_id; if cnt=
缺點:需要設計DB訊息表,同時還需要一個後臺任務,不斷掃描本地訊息。導致訊息的處理和業務邏輯耦合額外增加業務方的負擔。
-
-
分散式事務 - RocketMQ 事務訊息
- 基本原理:
- 事務發起方首先發送 prepare 訊息到 MQ。
- 在傳送 prepare 訊息成功後執行本地事務。
- 根據本地事務執行結果返回 commit 或者是 rollback。
- 如果訊息是 rollback,MQ 將刪除該 prepare 訊息不進行下發,如果是 commit 訊息,MQ 將會把這個訊息傳送給 consumer 端。
- 如果執行本地事務過程中,執行端掛掉,或者超時,MQ 將會不停的詢問其同組的其他 producer 來獲取狀態。
- Consumer 端的消費成功機制有 MQ 保證
- 基本原理:
-
如果事務訊息不能夠解決以上存在的問題,比如傳送端傳送成功但接受端一直失敗,此時狀態下,應當使用人工介入進行回滾。但回滾代價巨大,應儘量避免。
-
目前較多的分散式事務解決方案:
-
結合MQ訊息中介軟體實現可靠傳輸(目前電商最為流行的方式)
-
TCC補償性事務解決方案
-
最大努力通知型方案
第一種方案:可靠訊息最終一致性,需要業務系統結合MQ訊息中介軟體實現,在實現過程中需要保證訊息的成功傳送及成功消費。即需要通過業務系統控制MQ的訊息狀態
第二種方案:TCC補償性,分為三個階段TRYING-CONFIRMING-CANCELING。每個階段做不同的處理. TRYING階段主要是對業務系統進行檢測及資源預留
CONFIRMING階段是做業務提交,通過TRYING階段執行成功後,再執行該階段。預設如果TRYING階段執行成功,CONFIRMING就一定能成功。
CANCELING階段是回對業務做回滾,在TRYING階段中,如果存在分支事務TRYING失敗,則需要呼叫CANCELING將已預留的資源進行釋放。
第三種方案:最大努力通知xing型,這種方案主要用在與第三方系統通訊時,比如:呼叫微信或支付寶支付後的支付結果通知。這種方案也是結合MQ進行實現,例如:通過MQ傳送http請求,設定最大通知次數。達到通知次數後即不再通知。
-
-
主流的開源MQ(ActiveMQ、RabbitMQ、Kafka、redis)RocketMQ(alibaba)