分佈式事務Seata

官方文檔:http://seata.io/zh-cn/docs/overview/what-is-seata.html

1、Seata流程概述

參考 http://www.dreamwu.com/post-1741.html

2、SpringCloud+Eureka+Seata1.4.2 整合

參考 https://www.jianshu.com/p/90b0995d57bb

3、源碼流程解讀

打開 SeataAutoConfiguration,代碼不多,都是關鍵代碼

38行的 @ConditionalOnProperty  指定bean註冊的環境,只有在seata.enabled爲true時。若找不到這個屬性默認爲true

接下來的 failureHandler,當沒有自定義實現時,會返回一個默認的實現。

然後就是globalTransactionScanner,看名字就知道跟全局事務有關聯。看源碼。

AbstractAutoProxyCreator 對使用全局事務註解的bean動態代理

實現InitialzingBean afterPropertiesSet初始化

實現ApplicationContextAware對ApplicationContext操作

ConfigurationChangeListener 配置修改監聽器,實現註冊配置訂閱事件監聽器和配置中心動態訂閱功能與適配。

代理方法 wrapIfNecessary裏面交給 GlobalTransactionalInterceptor 接管

在invoke方法裏,對使用了GlobalTransactional和GlobalLock的bean進行代理,handleGlobalTransaction和handleGlobalLock兩個方法。

handleGlobalTransaction直接調用事務模板類template的execute方法。

    Object handleGlobalTransaction(final MethodInvocation methodInvocation,
        final GlobalTransactional globalTrxAnno) throws Throwable {
        boolean succeed = true;
        try {
            return transactionalTemplate.execute(new TransactionalExecutor() {
                @Override
                public Object execute() throws Throwable {
                    return methodInvocation.proceed();
                }

                public String name() {
                    String name = globalTrxAnno.name();
                    if (!StringUtils.isNullOrEmpty(name)) {
                        return name;
                    }
                    return formatMethod(methodInvocation.getMethod());
                }

                @Override
                public TransactionInfo getTransactionInfo() {
                    // reset the value of timeout
                    int timeout = globalTrxAnno.timeoutMills();
                    if (timeout <= 0 || timeout == DEFAULT_GLOBAL_TRANSACTION_TIMEOUT) {
                        timeout = defaultGlobalTransactionTimeout;
                    }

                    TransactionInfo transactionInfo = new TransactionInfo();
                    transactionInfo.setTimeOut(timeout);
                    transactionInfo.setName(name());
                    transactionInfo.setPropagation(globalTrxAnno.propagation());
                    transactionInfo.setLockRetryInternal(globalTrxAnno.lockRetryInternal());
                    transactionInfo.setLockRetryTimes(globalTrxAnno.lockRetryTimes());
                    Set<RollbackRule> rollbackRules = new LinkedHashSet<>();
                    for (Class<?> rbRule : globalTrxAnno.rollbackFor()) {
                        rollbackRules.add(new RollbackRule(rbRule));
                    }
                    for (String rbRule : globalTrxAnno.rollbackForClassName()) {
                        rollbackRules.add(new RollbackRule(rbRule));
                    }
                    for (Class<?> rbRule : globalTrxAnno.noRollbackFor()) {
                        rollbackRules.add(new NoRollbackRule(rbRule));
                    }
                    for (String rbRule : globalTrxAnno.noRollbackForClassName()) {
                        rollbackRules.add(new NoRollbackRule(rbRule));
                    }
                    transactionInfo.setRollbackRules(rollbackRules);
                    return transactionInfo;
                }
            });
        } catch (TransactionalExecutor.ExecutionException e) {
            TransactionalExecutor.Code code = e.getCode();
            switch (code) {
                case RollbackDone:
                    throw e.getOriginalException();
                case BeginFailure:
                    succeed = false;
                    failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
                    throw e.getCause();
                case CommitFailure:
                    succeed = false;
                    failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
                    throw e.getCause();
                case RollbackFailure:
                    failureHandler.onRollbackFailure(e.getTransaction(), e.getOriginalException());
                    throw e.getOriginalException();
                case RollbackRetrying:
                    failureHandler.onRollbackRetrying(e.getTransaction(), e.getOriginalException());
                    throw e.getOriginalException();
                default:
                    throw new ShouldNeverHappenException(String.format("Unknown TransactionalExecutor.Code: %s", code));
            }
        } finally {
            if (degradeCheck) {
                EVENT_BUS.post(new DegradeCheckEvent(succeed));
            }
        }
    }

發生異常catch後,會獲取 TransactionalExecutor.Code code = e.getCode(),根據這個code,調用failureHandler相應的方法(可自定義實現)

最後在finally中發送消息到事務總線。

TransactionalTemplate的execute方法

>>>>>>>>>  未完待續 >>>>>>>>>

4、 seata怎麼處理回滾和提交等操作

使用定時線程池類 io.seata.server.coordinator.DefaultCoordinator

    private ScheduledThreadPoolExecutor retryRollbacking = new ScheduledThreadPoolExecutor(1,
        new NamedThreadFactory("RetryRollbacking", 1));

    private ScheduledThreadPoolExecutor retryCommitting = new ScheduledThreadPoolExecutor(1,
        new NamedThreadFactory("RetryCommitting", 1));

    private ScheduledThreadPoolExecutor asyncCommitting = new ScheduledThreadPoolExecutor(1,
        new NamedThreadFactory("AsyncCommitting", 1));

    private ScheduledThreadPoolExecutor timeoutCheck = new ScheduledThreadPoolExecutor(1,
        new NamedThreadFactory("TxTimeoutCheck", 1));

    private ScheduledThreadPoolExecutor undoLogDelete = new ScheduledThreadPoolExecutor(1,
        new NamedThreadFactory("UndoLogDelete", 1));

5、怎麼控制事務失敗回滾重試

## server configuration, only used in server side
server {
  recovery {
    #schedule committing retry period in milliseconds
    committingRetryPeriod = 1000
    #schedule asyn committing retry period in milliseconds
    asynCommittingRetryPeriod = 1000
    #schedule rollbacking retry period in milliseconds
    rollbackingRetryPeriod = 1000
    #schedule timeout retry period in milliseconds
    timeoutRetryPeriod = 1000
  }
  undo {
    logSaveDays = 7
    #schedule delete expired undo_log in milliseconds
    logDeletePeriod = 86400000
  }
  #check auth
  enableCheckAuth = true
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  maxCommitRetryTimeout = "-1"
  maxRollbackRetryTimeout = "30000"
  rollbackRetryTimeoutUnlockEnable = false
  retryDeadThreshold = 130000
}

server.recovery 中4個重試期間值,在 io.seata.server.coordinator.DefaultCoordinator#init 方法裏初始化

maxRollbackRetryTimeout 默認值是-1,表示會回滾失敗會一直重試。

示例調整爲30000毫秒,從全局事務開始計算時間,在源碼中 io.seata.server.coordinator.DefaultCoordinator#handleRetryRollbacking 方法裏用到

 

 

 

 

 

 

 

 

 

 

 

 

 

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