Spring Boot微服務如何集成seata解決分佈式事務問題?

什麼是fescar?

  關於fescar的詳細介紹,請參閱fescar wiki

  傳統的2PC提交協議,會持有一個全局性的鎖,所有局部事務預提交成功後一起提交,或有一個局部事務預提交失敗後一起回滾,最後釋放全局鎖。鎖持有的時間較長,會對併發造成較大的影響,死鎖的風險也較高。

  fescar的創新之處在於,每個局部事務執行完立即提交,釋放本地鎖;它會去解析你代碼中的sql,從數據庫中獲得事務提交前的事務資源即數據,存放到undo_log中,全局事務協調器在回滾的時候直接使用undo_log中的數據覆蓋你提交的數據。

Spring Boot如何集成fescar?

  我們可以從官方代碼庫中看到,fescar目前提供的示例是針對使用dubbo的服務,那Spring Boot的項目如何集成fescar呢?

  

  和很多2PC提交協議(如tx_lcn)的解決方案一樣,fescar也是在數據源處做了代理,和事務協調器進行通信,來決定本地事務是否回滾。所以,第一步,在你的spring boot項目中,首先應使用fescar提供的代理數據源作爲你的數據源,例如:

            DruidDataSource dataSource = initDataSource(dataSourceProps.get("url").toString(), dataSourceProps.get("username").toString(), dataSourceProps.get("password").toString());
            DataSourceProxy proxy = new DataSourceProxy(dataSource);

  然後,你需要創建一個Feign攔截器,把RootContext中的XID(XID用於標識一個局部事務屬於哪個全局事務,需要在調用鏈路的上下文中傳遞)傳遞到上層調用鏈路。

@Component
public class RequestHeaderInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String xid = RootContext.getXID();
        if(StringUtils.isNotBlank(xid)){
            template.header("Fescar-Xid",xid);
        }
    }
}

  最後,你需要創建一個Http Rest請求攔截器,用於把當前上下文中獲取到的XID放到RootContext。

import com.alibaba.fescar.core.context.RootContext;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FescarXidFilter extends OncePerRequestFilter {
    protected Logger logger = LoggerFactory.getLogger(FescarXidFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String xid = RootContext.getXID();
        String restXid = request.getHeader("Fescar-Xid");
        boolean bind = false;
        if(StringUtils.isBlank(xid)&&StringUtils.isNotBlank(restXid)){
            RootContext.bind(restXid);
            bind = true;
            if (logger.isDebugEnabled()) {
                logger.debug("bind[" + restXid + "] to RootContext");
            }
        }
        try{
            filterChain.doFilter(request, response);
        } finally {
            if (bind) {
                String unbindXid = RootContext.unbind();
                if (logger.isDebugEnabled()) {
                    logger.debug("unbind[" + unbindXid + "] from RootContext");
                }
                if (!restXid.equalsIgnoreCase(unbindXid)) {
                    logger.warn("xid in change during http rest from " + restXid + " to " + unbindXid);
                    if (unbindXid != null) {
                        RootContext.bind(unbindXid);
                        logger.warn("bind [" + unbindXid + "] back to RootContext");
                    }
                }
            }
        }
    }
}

  這樣就完成了fescar的集成。

開始使用吧!

  首先在項目中初始化兩個Bean:

    @Bean
    public FescarXidFilter fescarXidFilter(){
        return new FescarXidFilter();
    }

    @Bean
    public GlobalTransactionScanner scanner(){
        GlobalTransactionScanner scanner = new GlobalTransactionScanner("fescar-test","my_test_tx_group");
        return scanner;
    }

  然後寫兩個服務,服務A調用服務B,並在A服務的調用方法上打上@GlobalTransactional標籤:

    @GlobalTransactional(timeoutMills = 300000, name = "fescar-test-tx")
    public void testFescar() throws BusinessException {
        DictionVO dictionVO = new DictionVO();
        dictionVO.setCode("simidatest");
        dictionVO.setValue("1");
        dictionVO.setDesc("simidatest");
        dictionVO.setAppId("sso");
        commonService.createDiction(dictionVO);//遠程調用服務B
        areaMapper.deleteAreaBySysNo(2);//本地事務

        throw new BusinessException("主動報錯");
    }

  最後,兩個項目中添加application.conf文件,用於告訴客戶端如何與分佈式協調器通信,官方示例中有這個文件,就不在此貼代碼啦,application.conf傳送門

啓動事務協調器,sh fescar-server.sh 8091 ~/dksl/git/fescar/data,啓動你的項目,開始測試吧!

  demo地址:https://github.com/dk-lockdown/seata-demo

  集成代碼:dk-foundation seata分支(https://github.com/dk-lockdown/dk-foundation/tree/dev-seata

last thing

  分佈式事務作爲微服務應用中的老大難問題,在現有的解決方案中,個人認爲fescar是目前最輕量並且代價最小的一種解決方案。目前的版本,事務協調器還不能分佈式部署,官方給出的路線圖是在三月底會有第一個生產可用版本。讓我們一起參與到fescar的社區中,共同推動fescar生態建設,讓落地微服務不必再擔心分佈式事務的問題。

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