分散式事務 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 將相關聯的訊息傳送到相同