分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

芋道原始碼_以德服人_不服就幹發表於2018-03-03

摘要: 原創出處 http://www.iocoder.cn/TCC-Transaction/console/ 「芋道原始碼」歡迎轉載,保留摘要,謝謝!

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


分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

???關注**微信公眾號:【芋道原始碼】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有原始碼分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文註釋原始碼 GitHub 地址
  3. 您對於原始碼的疑問每條留言將得到認真回覆。甚至不知道如何讀原始碼也可以請教噢
  4. 新的原始碼解析文章實時收到通知。每週更新一篇左右
  5. 認真的原始碼交流微信群。

1. 概述

本文分享 運維平臺。TCC-Transaction 提供了相對精簡的運維平臺,用於檢視在《TCC-Transaction 原始碼分析 —— 事務儲存器》提到的事務儲存。目前暫時只有兩個功能:

  • 檢視未完成的事務列表
  • 重置事務恢復重試次數

運維平臺( Maven 專案 tcc-transaction-server ) 整體程式碼結構如下:

分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

本文自下而上,Dao => Controller => UI 的順序進行解析實現。

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

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

2. 資料訪問層

org.mengyun.tcctransaction.server.dao.TransactionDao,事務Dao 介面,實現程式碼如下:

public interface TransactionDao {

    /**
     * 獲得事務 VO 陣列
     *
     * @param domain 領域
     * @param pageNum 第幾頁
     * @param pageSize 分頁大小
     * @return 事務 VO 陣列
     */
    List<TransactionVo> findTransactions(String domain, Integer pageNum, int pageSize);

    /**
     * 獲得事務總數量
     *
     * @param domain 領域
     * @return 數量
     */
    Integer countOfFindTransactions(String domain);

    /**
     * 重置事務重試次數
     *
     * @param domain 領域
     * @param globalTxId 全域性事務編號
     * @param branchQualifier 分支事務編號
     * @return 是否重置成功
     */
    boolean resetRetryCount(String domain, byte[] globalTxId, byte[] branchQualifier);
}
複製程式碼

TCC-Transaction 提供了四種事務儲存器,但是目前只支援兩種資料訪問層的實現:

  • JDBC 事務 DAO
  • Redis 事務 DAO

2.1 JDBC 事務 DAO

org.mengyun.tcctransaction.server.dao.JdbcTransactionDao,JDBC 事務 DAO 實現。實現程式碼如下:

@Repository("jdbcTransactionDao")
public class JdbcTransactionDao implements TransactionDao {

    private static final String TABLE_NAME_PREFIX = "TCC_TRANSACTION";

    @Autowired
    private DataSource dataSource;

    /**
     * 讀取 jdbc-domain-suffix.properties
     */
    @Value("#{jdbcDomainSuffix}")
    private Properties domainSuffix;
    
    // ... 省略程式碼
}
複製程式碼
  • dataSource,資料來源。配置方式如下:

    // appcontext-server-dao.xml 
    <bean id="dataSource"
         class="org.apache.commons.dbcp.BasicDataSource"
         destroy-method="close">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="${jdbc.url}"/>
       <property name="username" value="${jdbc.username}"/>
       <property name="password" value="${jdbc.password}"/>
       <property name="maxActive" value="50"/>
       <property name="minIdle" value="5"/>
       <property name="maxIdle" value="20"/>
       <property name="initialSize" value="30"/>
       <property name="logAbandoned" value="true"/>
       <property name="removeAbandoned" value="true"/>
       <property name="removeAbandonedTimeout" value="10"/>
       <property name="maxWait" value="1000"/>
       <property name="timeBetweenEvictionRunsMillis" value="10000"/>
       <property name="numTestsPerEvictionRun" value="10"/>
       <property name="minEvictableIdleTimeMillis" value="10000"/>
       <property name="validationQuery" value="SELECT NOW() FROM DUAL"/>
    </bean>
    
    // tcc-transaction-server.properties
    jdbc.url=jdbc:mysql://127.0.0.1:33061/TCC?useUnicode=true&characterEncoding=UTF-8
    jdbc.username=root
    jdbc.password=123456
    複製程式碼
    • appcontext-server-dao.xml,配置資料來源 Bean 物件。
    • tcc-transaction-server.properties,配置資料來源屬性。
  • domainSuffixdomian 和 表字尾( suffix ) 的對映關係。配置方式如下:

    // jdbc-domain-suffix.properties
    CAPITAL=_CAP
    ORDER=_ORD
    REDPACKET=_RED
    複製程式碼
    • 鍵 :domain。
    • 值 :suffix。

JdbcTransactionDao 程式碼實現上比較易懂,點選連結檢視,已經新增中文註釋。

2.2 Redis 事務 DAO

org.mengyun.tcctransaction.server.dao.RedisTransactionDao,Redis 事務 DAO。實現程式碼如下:

@Repository("redisTransactionDao")
public class RedisTransactionDao implements TransactionDao {

    /**
     * redis pool
     */
    @Autowired
    private JedisPool jedisPool;

    /**
     * 序列化
     */
    private ObjectSerializer serializer = new JdkSerializationSerializer();

    /**
     * 讀取 redis-domain-key-prefix.properties
     */
    @Value("#{redisDomainKeyPrefix}")
    private Properties domainKeyPrefix;
}
複製程式碼
  • jedisPool,Redis 連線池。配置方式如下:

    // appcontext-server-dao.xml
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
       <property name="maxTotal" value="300"/>
       <property name="maxIdle" value="100"/>
       <property name="minIdle" value="10"/>
       <property name="maxWaitMillis" value="3000"/>
    </bean>
    
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
       <constructor-arg index="0" ref="jedisPoolConfig"/>
       <constructor-arg index="1" value="${redis.host}"/>
       <constructor-arg index="2" value="${redis.port}" type="int"/>
       <constructor-arg index="3" value="6000" type="int"/>
       <constructor-arg index="4" type="java.lang.String">
           <null/>
       </constructor-arg>
       <constructor-arg index="5" value="${redis.db}" type="int"/>
    </bean>
    
    // tcc-transaction-server.properties
    redis.host=127.0.0.1
    redis.port=6379
    redis.password=
    redis.db=0
    複製程式碼
    • appcontext-server-dao.xml,配置 Redis 連線池 Bean 物件。
    • tcc-transaction-server.properties,配置 Redis 連線池屬性。
  • domainKeyPrefix,domain 和 Redis Key 字首( prefix )的對映。配置方式如下:

    CAPITAL=TCC:CAP:
    ORDER=TCC:ORD:
    REDPACKET=TCC:RED:
    複製程式碼
    • 鍵 :domain。
    • 值 :suffix。

RedisTransactionDao 程式碼實現上比較易懂,點選[連結]https://github.com/YunaiV/tcc-transaction/blob/e54c3e43a2e47a7765bdb18a485860cb31acbb72/tcc-transaction-server/src/main/java/org/mengyun/tcctransaction/server/dao/RedisTransactionDao.java)檢視,已經新增中文註釋。

3. 控制層

org.mengyun.tcctransaction.server.controller.TransactionController,事務 Controller。實現程式碼如下:

@Controller
public class TransactionController {

    public static final Integer DEFAULT_PAGE_NUM = 1;

    public static final int DEFAULT_PAGE_SIZE = 10;

    /**
     * 資料訪問物件
     */
    @Autowired
    @Qualifier("jdbcTransactionDao")
    private TransactionDao transactionDao;

    /**
     * 專案訪問根目錄
     */
    @Value("${tcc_domain}")
    private String tccDomain;
}
複製程式碼
  • transactionDao,資料訪問物件。配置方式如下:

    // appcontext-server-dao.xml
    <bean id="transactionDao" class="org.mengyun.tcctransaction.server.dao.JdbcTransactionDao"/>
    複製程式碼
    • 目前運維平臺只能讀取一個資料來源,如果你的資料來源是多個,需要對運維平臺做一定的改造,或啟動多個專案。
  • tccDomain,專案訪問根目錄。配置方式如下:

    // tcc-transaction-server.properties
    tcc_domain=
    複製程式碼
    • 一般情況下不用配置,如果你放在 Tomcat 根目錄。

3.1 檢視未完成的事務列表

呼叫 TransactionController#manager(...) 方法,檢視事務列表。實現程式碼如下:

@RequestMapping(value = "/management", method = RequestMethod.GET)
public ModelAndView manager() {
   return new ModelAndView("manager");
}

@RequestMapping(value = "/management/domain/{domain}", method = RequestMethod.GET)
public ModelAndView manager(@PathVariable String domain) {
   return manager(domain, DEFAULT_PAGE_NUM);
}

@RequestMapping(value = "/management/domain/{domain}/pagenum/{pageNum}", method = RequestMethod.GET)
public ModelAndView manager(@PathVariable String domain, @PathVariable Integer pageNum) {
   ModelAndView modelAndView = new ModelAndView("manager");
   // 獲得事務 VO 陣列
   List<TransactionVo> transactionVos = transactionDao.findTransactions(domain, pageNum, DEFAULT_PAGE_SIZE);
   // 獲得事務總數量
   Integer totalCount = transactionDao.countOfFindTransactions(domain);
   // 計算總頁數
   Integer pages = totalCount / DEFAULT_PAGE_SIZE;
   if (totalCount % DEFAULT_PAGE_SIZE > 0) {
       pages++;
   }
   // 返回
   modelAndView.addObject("transactionVos", transactionVos);
   modelAndView.addObject("pageNum", pageNum);
   modelAndView.addObject("pageSize", DEFAULT_PAGE_SIZE);
   modelAndView.addObject("pages", pages);
   modelAndView.addObject("domain", domain);
   modelAndView.addObject("urlWithoutPaging", tccDomain + "/management/domain/" + domain);
   return modelAndView;
}
複製程式碼

UI 介面如下:

分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

3.2 重置事務恢復重試次數

呼叫 TransactionController#reset(...) 方法,事務重置重試次數。實現程式碼如下:

@RequestMapping(value = "/domain/{domain}/retry/reset", method = RequestMethod.PUT)
@ResponseBody
public CommonResponse<Void> reset(@PathVariable String domain, String globalTxId, String branchQualifier) {
   transactionDao.resetRetryCount(domain,
           DatatypeConverter.parseHexBinary(globalTxId),
           DatatypeConverter.parseHexBinary(branchQualifier));
   return new CommonResponse<Void>();
}
複製程式碼

UI 介面如下:

分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

666. 彩蛋

知識星球

可能有人會吐槽運維平臺怎麼做的這麼簡陋。這個不是 TCC-Transaction 一個開源專案存在的問題,其他例如 Dubbo、Disconf 等等都會存在這個情況。

開源作者因為時間關係,更多的精力關注在核心程式碼,所以對運維友好性可能花費的精力較少。

當然,因為是開源的關係,我們可以自己做運維平臺反向的貢獻到這些專案。

分散式事務 TCC-Transaction 原始碼分析 —— 運維平臺

胖友,分享一個朋友圈可好?

相關文章