歡迎光臨
每天分享高質量文章

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

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

  • 1. 概述

  • 2. 資料訪問層

    • 2.1 JDBC 事務 DAO

    • 2.2 Redis 事務 DAO

  • 3. 控制層

    • 3.1 檢視未完成的事務串列

    • 3.2 重置事務恢復重試次數

  • 666. 彩蛋


友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。

1. 概述

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

  • 檢視未完成的事務串列

  • 重置事務恢復重試次數

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

本文自下而上,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 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 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 介面如下:

    3.2 重置事務恢復重試次數

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

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

    UI 介面如下:

    666. 彩蛋

    知識星球

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

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

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

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

    贊(0)

    分享創造快樂