1. 程式人生 > >分散式事務 TCC-Transaction 原始碼分析 —— TCC 實現

分散式事務 TCC-Transaction 原始碼分析 —— TCC 實現

本文主要基於 TCC-Transaction 1.2.3.3 正式版

  • 1. 概述

  • 2. TCC 原理

  • 3. TCC-Transaction 原理

  • 4. 事務與參與者

    • 4.1 事務

    • 4.2 參與者

  • 5. 事務管理器

    • 5.1 發起根事務

    • 5.2 傳播發起分支事務

    • 5.3 傳播獲取分支事務

    • 5.4 提交事務

    • 5.5 回滾事務

    • 5.6 新增參與者到事務

  • 6. 事務攔截器

    • 6.1 Compensable

    • 6.2 可補償事務攔截器

    • 6.3 資源協調者攔截器

  • 666. 彩蛋

友情提示:歡迎關注公眾號【芋道原始碼】。?關注後,拉你進【原始碼圈】微信群和【芋艿】搞基嗨皮。

友情提示:歡迎關注公眾號【芋道原始碼】。?關注後,拉你進【原始碼圈】微信群和【芋艿】】搞基嗨皮。

友情提示:歡迎關注公眾號【芋道原始碼】。?關注後,拉你進【原始碼圈】微信群和【芋艿】】搞基嗨皮。

1. 概述

本文分享 TCC 實現。主要涉及如下三個 Maven 專案:

  • tcc-transaction-core :tcc-transaction 底層實現。

  • tcc-transaction-api :tcc-transaction 使用 API。

  • tcc-transaction-spring :tcc-transaction Spring 支援。

你行好事會因為得到讚賞而愉悅 
同理,開源專案貢獻者會因為 Star 而更加有動力 
為 TCC-Transaction 點贊!傳送門

OK,開始我們的第一段 TCC 旅程吧。

ps:筆者假設你已經閱讀過《tcc-transaction 官方文件 —— 使用指南1.2.x》。

ps2:未特殊說明的情況下,本文事務指的是 TCC事務

2. TCC 原理

FROM https://support.hwclouds.com/devg-servicestage/zh-cn_topic_0056814426.html 
TCC事務 
為了解決在事務執行過程中大顆粒度資源鎖定的問題,業界提出一種新的事務模型,它是基於業務層面的事務定義。鎖粒度完全由業務自己控制。它本質是一種補償的思路。它把事務執行過程分成 Try、Confirm / Cancel 兩個階段。在每個階段的邏輯由業務程式碼控制。這樣就事務的鎖粒度可以完全自由控制。業務可以在犧牲隔離性的情況下,獲取更高的效能。

  • Try 階段

    • 完成所有業務檢查( 一致性 )

    • 預留必須業務資源( 準隔離性 )

    • Try :嘗試執行業務

  • Confirm / Cancel 階段:

    • 釋放 Try 階段預留的業務資源

    • Cancel 操作滿足冪等性

    • 真正執行業務

    • 不做任務業務檢查

    • Confirm 操作滿足冪等性

    • Confirm :確認執行業務

    • Cancel :取消執行業務

    • Confirm 與 Cancel 互斥

整體流程如下圖:

  • 紅框部分功能由 tcc-transaction-core 實現:

    • 啟動業務活動

    • 登記業務操作

    • 提交 / 回滾業務活動

  • 黃框部分功能由 tcc-transaction-http-sample 實現( 官方提供的示例專案 ):

    • Try 操作

    • Confirm 操作

    • Cancel 操作

與 2PC協議 比較

  • 位於業務服務層而非自願層

  • 沒有單獨的準備( Prepare )階段,Try 操作兼備自願操作與準備能力

  • Try 操作可以靈活選擇業務資源的鎖定粒度

  • 較高開發成本

參考資料:

  • 《支付寶運營架構中柔性事務指的是什麼?》

  • 《分散式事務的典型處理方式:2PC、TCC、非同步確保和最大努力型》

3. TCC-Transaction 原理

在 TCC 裡,一個業務活動可以有多個事務,每個業務操作歸屬於不同的事務,即一個事務可以包含多個業務操作。TCC-Transaction 將每個業務操作抽象成事務參與者,每個事務可以包含多個參與者

參與者需要宣告 try / confirm / cancel 三個型別的方法,和 TCC 的操作一一對應。在程式裡,通過 @Compensable 註解標記在 try 方法上,並填寫對應的 confirm / cancel 方法,示例程式碼如下:

// try
@Compensable(confirmMethod = "confirmRecord", cancelMethod = "cancelRecord", transactionContextEditor = MethodTransactionContextEditor.class)
public String record(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {}

// confirm
public void confirmRecord(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {}

// cancel
public void cancelRecord(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {}
  • 在示例程式碼中,我們看到 TransactionContext,事務上下文,這個是怎麼生成的呢?這裡先賣一個關子。

TCC-Transaction 有兩個攔截器,通過對 @Compensable AOP 切面( 參與者 try 方法 )進行攔截,透明化對參與者 confirm / cancel 方法呼叫,從而實現 TCC 。簡化流程如下圖:

第一個攔截器,可補償事務攔截器,實現如下功能:

  • 在 Try 階段,對事務的發起、傳播。

  • 在 Confirm / Cancel 階段,對事務提交或回滾。

  • 為什麼會有對事務的傳播呢?在遠端呼叫服務的參與者時,會通過"引數"( 需要序列化 )的形式傳遞事務給遠端參與者。

第二個攔截器,資源協調者攔截器,實現如下功能:

  • 在 Try 階段,新增參與者到事務中。當事務上下文不存在時,進行建立。

實際攔截器對事務的處理會比上圖複雜一些,在本文「6. 事務攔截器」詳細解析。

在 TCC-Transaction 程式碼實現上,元件分層如下圖:

本文按照如下順序分享:

  • 「4. 事務攔截器」

  • 「5. 事務管理器」

  • 「6. 事務管理器」

內容是自下而上的方式分享,每個元件可以更加整體的被認識。當然這可能對你理解時產生一臉悶逼,所以推薦兩種閱讀方式:

  • 簡讀 x 1 + 深讀 x 1

  • 倒著讀,發現未分享的方法,全文檢索該方法。

事務儲存器在《TCC-Transaction 原始碼解析 —— 事務儲存於恢復》詳細解析。

事務恢復在《TCC-Transaction 原始碼解析 —— 事務恢復》詳細解析。

4. 事務與參與者

在 TCC 裡,一個事務( org.mengyun.tcctransaction.Transaction ) 可以有多個參與者( org.mengyun.tcctransaction.Participant )參與業務活動。類圖關係如下( 開啟大圖 ):

4.1 事務

Transaction 實現程式碼如下

public class Transaction implements Serializable {

   private static final long serialVersionUID = 7291423944314337931L;

   /**
    * 事務編號
    */

   private TransactionXid xid;
   /**
    * 事務狀態
    */

   private TransactionStatus status;
   /**
    * 事務型別
    */

   private TransactionType transactionType;
   /**
    * 重試次數
    */

   private volatile int retriedCount = 0;
   /**
    * 建立時間
    */

   private Date createTime = new Date();
   /**
    * 最後更新時間
    */

   private Date lastUpdateTime = new Date();
   /**
    * 版本號
    */

   private long version = 1;
   /**
    * 參與者集合
    */

   private List<Participant> participants = new ArrayList<Participant>();
   /**
    * 附帶屬性對映
    */

   private Map<String, Object> attachments = new ConcurrentHashMap<String, Object>();

   /**
    * 新增參與者
    *
    * @param participant 參與者
    */

   public void enlistParticipant(Participant participant) {
       participants.add(participant);
   }

   /**
    * 提交 TCC 事務
    */

   public void commit() {
       for (Participant participant : participants) {
           participant.commit();
       }
   }

   /**
    * 回滾 TCC 事務
    */

   public void rollback() {
       for (Participant participant : participants) {
           participant.rollback();
       }
   }
}
  • xid,事務編號( TransactionXid ),用於唯一標識一個事務。使用 UUID 演算法生成,保證唯一性org.mengyun.tcctransaction.api.TransactionXid 實現 javax.transaction.xa.Xid 介面,實現程式碼如下:

    public class TransactionXid implements Xid, Serializable {
       private static final long serialVersionUID = -6817267250789142043L;
    /**

    相關推薦

    分散式學習筆記十三:分散式事務 TCC-Transaction 原始碼分析 —— TCC 實現

    本文主要基於 TCC-Transaction 1.2.3.3 正式版 1. 概述 本文分享 TCC 實現。主要涉及如下三個 Maven 專案: tcc-transaction-core :tcc-transaction 底層實現。 tcc-transaction-ap

    分散式事務 TCC-Transaction 原始碼分析 —— TCC 實現

    本文主要基於 TCC-Transaction 1.2.3.3 正式版1. 概述2. TCC 原理

    分散式事務中介軟體 TCC-Transaction 原始碼分析 —— Dubbo 支援

    1. 概述 本文分享 Dubbo 支援。 TCC-Transaction 通過 Dubbo 隱式傳參的功能,避免自己對業務程式碼的入侵。可能有同學不太理解為什麼說 TCC-Transaction 對業務程式碼有一定的入侵性,一起來看個程式碼例子: 程式碼來自 t

    python分散式事務方案(一)tcc

    python分散式事務方案(一)tcc 隨著單體應用的拆分以及服務化的流行,現在分散式事務已經比較常見,分散式事務理論ACID、CAP、BASE等我就不說了,現在就直接說一下一種常見的解決方案-tcc TCC 其實就是採用的補償機制,其核心思想是:針對每個操作,都要註冊一個與其對應的確認和補償(

    Tomcat(二) Tomcat實現: Servlet與web.xml介紹 以及 原始碼分析Tomcat實現細節

    轉載自;http://blog.csdn.net/tjiyu/article/details/54590259     -------如有侵權  請聯絡我 我會進行刪除    在《Tomcat(一

    c++模板超程式設計:std::invoke原始碼分析及其實現

    在實現invoke之前,我們先看一下標準庫種invoke的使用方式 template< class F, class... Args>std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... ar

    【4】Netty4原始碼分析-NioEventLoop實現的執行緒執行邏輯

    轉自 http://xw-z1985.iteye.com/blog/1928244 在netty服務端啟動原始碼分析-執行緒建立一文中已分析SingleThreadEventExecutor所持有的執行緒的執行邏輯由NioEventLoop實現,那麼本文就著手分析NioEventLoop

    分散式事務之——基於訊息中介軟體實現

     環境需求:假如某人有5個女朋友(有點複雜),每天晚上都會給他的女朋友打電話說晚安,那麼每給一個女朋友打電話,其他女朋友都要進入等待狀態。一個一個打下去。。。等打到最後一個已經是凌晨了,對方都睡了。那麼有什麼辦法可以解決呢?此時這個人可以利用微信公眾號將自己甜言蜜語放進公眾號

    Opencv輪廓跟蹤演算法原始碼分析實現單步除錯——icvFetchContour()

    首先分析要除錯的圖的特性,使用畫圖工具手動定位到外輪廓的”起始點“在(77,126) 原圖如下: 呼叫的修改後的fushuwu_icvFetchContour()的實參如下: int main() { Mat img0 = imread("d:/test_co

    原始碼分析HashMap實現原理

    HashMap 基於雜湊表的 Map 介面的實現。此實現提供所有可選的對映操作,並允許使用 null 值和 null 鍵。(除了不同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證對映的順序,特別是它不保證該順序恆久不變。另外,HashMap是非

    Spring原始碼分析——Aop實現

    1、Aop概念回顧 Aop是Aspect-Oriented Programming(面向切面程式設計)的簡稱,維基百科對於它的解釋如下: Aspect是一種新的模組化機制,用來描述分佈的物件,類或函式中的橫切關注點,從關注點分離出橫切關注點是面向切面的程式設計

    手撕MyBatis底層原始碼分析實現

    MyBatis Hiberante 簡介 什麼是 MyBatis ? MyBatis 是一款優秀的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單

    LinkedHashMap原始碼分析實現LRU演算法

    PS: 要先了解HashMap的實現原理HashMap原始碼分析 一、簡單介紹 public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>

    Java BAT大型公司面試必考技能視訊教程之HashMap原始碼分析實現

    視訊通過以下四個方面介紹了HASHMAP的內容 一、 什麼是HashMap Hash雜湊將一個任意的長度通過某種演算法(Hash函式演算法)轉換成一個固定的值。 MAP:地圖 x,y 儲存 總結:通過HASH出來的值,然後通過值定位到這個MAP,然後value儲存到這個M

    面試必考之HashMap原始碼分析實現

    以下是JDK1.8之前版本的原始碼簡介 一、什麼是HashMap? Hash:雜湊將一個任意的長度通過某種(hash函式演算法)演算法轉換成一個固定值。 Map:儲存的集合、類似於地圖X,Y座

    分散式事務之最終一致的Mq實現

    問題的起源 分散式系統的特性 對分散式系統有過研究的讀者,可能聽說過“CAP定律”、“Base理論”等,非常巧的是,化學理論中ACID是酸、Base恰好是鹼。這裡我們不對這些概念做過多的解釋,有興趣的讀者可以檢視相關參考資料。 這裡針對一致性我

    分散式訊息佇列RocketMQ原始碼分析之3 -- Consumer負載均衡機制 -- Rebalance

    同Kafka一樣,RocketMQ也需要探討一個問題:如何把一個topic的多個queue分攤給不同的consumer,也就是負載均衡問題。 有興趣朋友可以關注公眾號“架構之道與術”, 獲取最新文章。 或掃描如下二維碼: 在討論這個問題之前,我們先看一

    STL list原始碼分析以及實現

    本文主要內容如下: 1. STL list實現的三個模組節點__list_node,迭代器__list_iterator以及list本身(使用一個__list_node*代表整個連結串列)的介紹。 2. 重點分析list的幾個核心函式,理解STL l

    分散式訊息佇列RocketMQ原始碼分析之2 -- Broker與NameServer心跳機制

    我們知道,Kafka是通過ZK的臨時節點來監測Broker的死亡的。當一個Broker掛了之後,ZK上面對應的臨時節點被刪除,同時其他Broker收到通知。 那麼在RocketMQ中,對應的NameServer是如何判斷一個Broker的死亡呢? 有興趣朋友

    分散式訊息佇列 RocketMQ 原始碼分析 —— Message 順序傳送與消費

    本文主要基於 RocketMQ 4.0.x 正式版 1. 概述 建議前置閱讀內容: 當然對 Message 傳送與消費已經有一定了解的同學,可以選擇跳過。 RocketMQ 提供了兩種順序級別: 普通順序訊息 :Producer 將相關聯的訊息傳送到相同