天天看點

消息隊列解決分布式事務消息隊列解決分布式事務

消息隊列解決分布式事務

  1. 本地消息表:通常處于同一張資料表,通過事務觸發器就能實作,但無法解決兩張表處于不同的資料庫問題
    begin transaction:
    update User set account = account - 100 where userId = 'A'
    insert into message(userId,amount,status) values('A',100,1)
    commit transaction
               
  2. 分布式事務-兩階段送出消息:
    • 基本原理:通過TC事務協調器,分别去确認A,B,C事務的發生,全部成功則使用TC進行送出,否則的話則進行abort
    • 缺點:涉及多次節點送出,通信時間太長;鎖定的資源也變得更多。
  3. 分布式事務 - 業務方自己實作(使用消息隊列來避免分布式事務),例子: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消息表,同時還需要一個背景任務,不斷掃描本地消息。導緻消息的處理和業務邏輯耦合額外增加業務方的負擔。
  4. 分布式事務 - RocketMQ 事務消息
    • 基本原理:
      1. 事務發起方首先發送 prepare 消息到 MQ。
      2. 在發送 prepare 消息成功後執行本地事務。
      3. 根據本地事務執行結果傳回 commit 或者是 rollback。
      4. 如果消息是 rollback,MQ 将删除該 prepare 消息不進行下發,如果是 commit 消息,MQ 将會把這個消息發送給 consumer 端。
      5. 如果執行本地事務過程中,執行端挂掉,或者逾時,MQ 将會不停的詢問其同組的其他 producer 來擷取狀态。
      6. Consumer 端的消費成功機制有 MQ 保證
  5. 如果事務消息不能夠解決以上存在的問題,比如發送端發送成功但接受端一直失敗,此時狀态下,應當使用人工介入進行復原。但復原代價巨大,應盡量避免。
  6. 目前較多的分布式事務解決方案:
    • 結合MQ消息中間件實作可靠傳輸(目前電商最為流行的方式)
    • TCC補償性事務解決方案
    • 最大努力通知型方案

      ​ 第一種方案:可靠消息最終一緻性,需要業務系統結合MQ消息中間件實作,在實作過程中需要保證消息的成功發送及成功消費。即需要通過業務系統控制MQ的消息狀态

      ​ 第二種方案:TCC補償性,分為三個階段TRYING-CONFIRMING-CANCELING。每個階段做不同的處理.

      ​ TRYING階段主要是對業務系統進行檢測及資源預留

      ​ CONFIRMING階段是做業務送出,通過TRYING階段執行成功後,再執行該階段。預設如果TRYING階段執行成功,CONFIRMING就一定能成功。

      ​ CANCELING階段是回對業務做復原,在TRYING階段中,如果存在分支事務TRYING失敗,則需要調用CANCELING将已預留的資源進行釋放。

      ​ 第三種方案:最大努力通知xing型,這種方案主要用在與第三方系統通訊時,比如:調用微信或支付寶支付後的支付結果通知。這種方案也是結合MQ進行實作,例如:通過MQ發送http請求,設定最大通知次數。達到通知次數後即不再通知。

  7. 主流的開源MQ(ActiveMQ、RabbitMQ、Kafka、redis)RocketMQ(alibaba)