分佈式事務鎖 —— Seata的TCC模式如何實現?

本文將介紹基於springcloud+feign使用阿里巴巴分佈式事務框架seata的TCC模式(1.0.0版本) ,AT模式基本上能滿足我們使用分佈式事務80%的需求。 但涉及非關係型數據庫與中間件的操作、跨公司服務的調用跨語言的應用調用需要結合TCC模式。關於seata的介紹可以點擊這裏進入seata官網。

一、TCC模式的概念

一個分佈式的全局事務,整體是兩階段提交(Try-[Comfirm/Cancel])的模型。在SEATA中,AT模式與TCC模式事實上都是基於兩階段提交實現。

他們的區別在於:

AT 模式基於 支持本地 ACID 事務 的 關係型數據庫

  • 一階段 prepare 行爲:在本地事務中,一併提交業務數據更新和相應回滾日誌記錄。
  • 二階段 commit 行爲:馬上成功結束,自動 異步批量清理回滾日誌。
  • 二階段 rollback 行爲:通過回滾日誌,自動 生成補償操作,完成數據回滾。

相應的,TCC 模式,不依賴於底層數據資源的事務支持:

  • 一階段 prepare 行爲:調用 自定義 的 prepare 邏輯。
  • 二階段 commit 行爲:調用 自定義 的 commit 邏輯。
  • 二階段 rollback 行爲:調用 自定義 的 rollback 邏輯。

所謂 TCC 模式,是指支持把 自定義 的分支事務納入到全局事務的管理中。

簡單點概括,SEATA的TCC模式就是手工的AT模式,它允許你自定義兩階段的處理邏輯而不依賴AT模式的undo_log。

二、TM與TCC-RM的搭建

準備nacos、seata服務端(TC), 着重講基於SpringCloud+Feign的TCC的實現,項目的搭建直接看源碼

1、seata服務端的搭建(TC事務協調者,略)

2、TM的搭建(TM全局事務控制,略)

3、TCC-RM的搭建(RM分支事務控制)

3.1 定義TCC接口

由於我們使用的是SpringCloud+Feign,Feign的調用基於http,因此此處我們使用LocalTCC便可。值得注意的是,@LocalTCC一定需要註解在接口上,此接口可以是尋常的業務接口,只要實現了TCC的兩階段提交對應方法便可。

  • @LocalTCC 適用於SpringCloud+Feign模式下的TCC
  • @TwoPhaseBusinessAction 註解try方法,其中name爲當前tcc方法的bean名稱,寫方法名便可(記得全局唯一),commitMethod指向提交方法,rollbackMethod指向事務回滾方法。指定好三個方法之後,seata會根據事務的成功或失敗,通過動態代理去幫我們自動調用提交或者回滾。
  • @BusinessActionContextParameter 註解可以將參數傳遞到二階段(commitMethod/rollbackMethod)的方法。
  • BusinessActionContext 便是指TCC事務上下文
/**
 * 這裏定義tcc的接口
 * 一定要定義在接口上
 * 我們使用springCloud的遠程調用
 * 那麼這裏使用LocalTCC便可
 *
 * @author tanzj
 */
@LocalTCC
public interface TccService {

    /**
     * 定義兩階段提交
     * name = 該tcc的bean名稱,全局唯一
     * commitMethod = commit 爲二階段確認方法
     * rollbackMethod = rollback 爲二階段取消方法
     * BusinessActionContextParameter註解 可傳遞參數到二階段方法
     *
     * @param params  -入參
     * @return String
     */
    @TwoPhaseBusinessAction(name = "insert", commitMethod = "commitTcc", rollbackMethod = "cancel")
    String insert(
            @BusinessActionContextParameter(paramName = "params") Map params
    );

    /**
     * 確認方法、可以另命名,但要保證與commitMethod一致
     * context可以傳遞try方法的參數
     *
     * @param context 上下文
     * @return boolean
     */
    boolean commitTcc(BusinessActionContext context);

    /**
     * 二階段取消方法
     *
     * @param context 上下文
     * @return boolean
     */
    boolean cancel(BusinessActionContext context);
}

3.2 TCC接口的業務實現

爲了保證代碼的簡潔,此處將Controller與Service結合講解,實際項目則不然。

  • 在try方法中使用@Transational可以直接通過spring事務回滾關係型數據庫中的操作,而非關係型數據庫等中間件的回滾操作可以交給rollbackMethod方法處理。
  • 使用context.getActionContext("params")便可以得到一階段try中定義的參數,在二階段對此參數進行業務回滾操作。
  • 注意,此處亦不可以捕獲異常(同理切面處理異常),否則TCC將識別該操作爲成功,二階段直接執行commitMethod。
  • 二階段commitMethod可以空確認。
@Slf4j
@RestController
public class TccServiceImpl implements  TccService {

    @Autowired
    TccDAO tccDAO;

    /**
     * tcc服務t(try)方法
     * 實際業務方法
     *
     * @param params - name
     * @return String
     */
    @Override
    @PostMapping("/tcc-insert")
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String insert(@RequestBody Map params) {
        log.info("------------------> xid = " + RootContext.getXID());
        //實際的操作,或操作MQ、redis等
        tccDAO.insert(params);
        //throw new RuntimeException("服務tcc測試回滾");
        return "success";
    }

    /**
     * tcc服務 confirm方法
     * 可以空確認
     *
     * @param context 上下文
     * @return boolean
     */
    @Override
    public boolean commitTcc(BusinessActionContext context) {
        log.info("xid = " + context.getXid() + "提交成功");
        return true;
    }

    /**
     * tcc 服務 cancel方法
     *
     * @param context 上下文
     * @return boolean
     */
    @Override
    public boolean cancel(BusinessActionContext context) {
        //todo 這裏寫中間件、非關係型數據庫的回滾操作
        System.out.println("please manually rollback this data:" + context.getActionContext("params"));
        return true;
    }
}

3.3 seata相關yml配置(單機版)

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: seataGroup-${seata.application-id}
  service:
    vgroup-mapping: default
    grouplist: 127.0.0.1:8091
  config:
    type: file
    file:
      name: file.conf
  registry:
    type: nacos
    file:
      name: file.conf

至此完成seata-tcc模式的配置工作。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章