1. 程式人生 > ># 訊息佇列解決分散式事務

# 訊息佇列解決分散式事務

訊息佇列解決分散式事務

  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)