消息隊列解決分佈式事務
-
本地消息表:通常處於同一張數據表,通過事務觸發器就能實現,但無法解決兩張表處於不同的數據庫問題
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==0 then update B set amount = amount + 10000; where userId =1; insert into mssage_apply(msg_id) values (msg.msg_id); //如果應用則將m中數據的id插入mssage_apply end transaction1 commit
缺點:需要設計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)