国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

TCC 開源項目源碼學(xué)習(xí)(一)

DTeam / 3113人閱讀

摘要:最終一致性通常使用消息機(jī)制來設(shè)計,其核心是消息的安全送達(dá)與消費(fèi)。事務(wù)狀態(tài),在的不通階段進(jìn)行事務(wù)狀態(tài)的變更。除了,最近項目中還涉及了安全消息,等弄清楚了再來一發(fā)。

TCC 開源項目源碼學(xué)習(xí)(一)

學(xué)習(xí)TCC分布式事務(wù)的知識是使用了GIT上的一個開源項目,之前有簡單的看過一些,有了一個大概的了解,但是隨著時間的‘清洗’,又開始變得‘渾濁不清’了,這次索性把這份源碼從頭看了下,又把流程推演了好幾次,覺得已經(jīng)懂了,想把理解的東西通過博客寫出來。在這個過程中,再次梳理一遍,加深理解,同時也可以發(fā)現(xiàn)一些理解偏差和錯誤的地方。
GIT: https://github.com/1755728288...

概要

在分布式系統(tǒng)中,為了保證執(zhí)行指令的正確性,引入了事務(wù)的概念。一般意義上,事務(wù)主要突出的是ACID,即原子性,一致性,隔離性和持久性。而在分布式事務(wù)中,最主要的原子性的保證,要保證一個業(yè)務(wù)操作在其分布式系統(tǒng)中的所有指令全部執(zhí)行或不執(zhí)行。因為各個指令的操作耗時以及順序,所以原子性都對應(yīng)了一定的時間窗口,比如單機(jī)系統(tǒng)下,這個時間窗口非常短,而且其原子性也由數(shù)據(jù)庫事務(wù)來保證。而在分布式系統(tǒng)中,原子性就依賴于具體的應(yīng)用設(shè)計了,主要的依據(jù)是業(yè)務(wù)上允許的時間窗口的長短。目前一般來說,若允許的時間窗口較短,就用TCC,若允許的時間窗口較長,則使用最終一致性。最終一致性通常使用消息機(jī)制來設(shè)計,其核心是消息的安全送達(dá)與消費(fèi)。

TCC可以說是一種設(shè)計模式,將傳統(tǒng)單機(jī)系統(tǒng)中的大事務(wù)進(jìn)行拆分,通過小事務(wù)來拼裝,并協(xié)調(diào)整體的事務(wù)提交和回滾。按字面意思理解,TCC主要分Try,Confirm,Cancel三個階段,Try預(yù)留資源,Confirm使用預(yù)留資源執(zhí)行業(yè)務(wù)操作,Cancel則是釋放資源。貌似簡單,但是在實際的業(yè)務(wù)場景中,往往會困惑我們在這三個階段分別要做什么,這個是業(yè)務(wù)設(shè)計的一部分內(nèi)容了,在此不展開敘述。不過要注意的一點時,任何一個階段的結(jié)果都是可見的,比如一個庫存子服務(wù)的入庫方法,在try階段就直接加到庫存上去了,回滾的時候發(fā)現(xiàn)剛加上的庫存已經(jīng)有買家下單準(zhǔn)備出庫了,那就GG了。

代碼結(jié)構(gòu)

先放個圖,這是項目的組件,上面綠色區(qū)域是框架的子模塊,下面黃色的是樣例模塊。不要被黃色區(qū)域嚇到,TCC的代碼不多,主要是tcc-transaction-core.

組件名 說明
tcc-transaction-core 【重要】核心代碼,主要的切面和job
tcc-transaction-api 注解和常量
tcc-transaction-spring spring使用的擴(kuò)展
tcc-transaction-dubbo dubbo使用時的擴(kuò)展
tcc-transaction-server tcc事務(wù)管理控制臺
tcc-transaction-unit-test 單元測試
tcc-transaction-tutorial-sample 訂單場景示例工程,分dubbo和spring版本

所以重點只有一個模塊,就是tcc-transaction-core,代碼量不多,主要分成下面的模塊

模塊名 說明
interceptor 【重要】2個切面,一個是根據(jù)事務(wù)狀態(tài)進(jìn)行tcc階段方法的選擇,一個是組織事務(wù)的參與者,用XID將各個參與者綁起來,以便事務(wù)的提交和回滾
recover 恢復(fù)在同步調(diào)用失敗事務(wù)的定時處理
repository 事務(wù)對象持久DAO對象,提供了多種選擇:緩存,文件系統(tǒng),jdbc,zookeeper
context 傳遞事務(wù)上下文的方法類,一般會在遠(yuǎn)程方法調(diào)用的切面中,將上下文加入到參數(shù)列表中
common 方法枚舉和事務(wù)枚舉
serializer 事務(wù)對象的序列化器,使用了kyto序列化工具
support 實現(xiàn)了工廠類,管理TCC的類的實例化
utils 工具類

最重要的是interceptor,是主要業(yè)務(wù)邏輯所在。

題外話,有人初看了一遍TCC,拿來和數(shù)據(jù)庫事務(wù)來比較,會說‘TCC不就是業(yè)務(wù)補(bǔ)償么,沒什么難點啊’,貌似有道理,其實不然。還記得數(shù)據(jù)庫事務(wù)的ACID嗎?因為數(shù)據(jù)庫提供了事務(wù)特性,ACID由數(shù)據(jù)庫保證,應(yīng)用只需要一個簡單的@Transactional注解就都搞定了。而分布式事務(wù),就把ACID的特性從數(shù)據(jù)庫里面拿了出來,由應(yīng)用程序來保證。當(dāng)然ACID也有了和之前不一樣的含義。

特性 數(shù)據(jù)庫 分布式事務(wù)
A[Atomicity] 所有數(shù)據(jù)庫更新一起提交和回滾,數(shù)據(jù)庫通過日志來實現(xiàn) 通過協(xié)調(diào)各個事務(wù)的參與方,通過框架來處理異常
C[Consistncy] 通過數(shù)據(jù)庫約束來實現(xiàn),比如非空,唯一,外鍵等
I[Isolation] 各個數(shù)據(jù)庫實現(xiàn)方式不一樣,主要分讀已提交,讀未提交等 TCC通過try階段鎖定資源來實現(xiàn)隔離,即業(yè)務(wù)資源的隔離
D[Durability] 數(shù)據(jù)庫實現(xiàn) 數(shù)據(jù)庫實現(xiàn)
工作流程

以項目中的例子來說明整個TCC的處理流程,這個例子是類似電商下單的場景,在支付的時候可以選擇紅包或本金,比如一個筆記本4000,可以選擇使用3000的本金和1000的紅包來支付,有三個服務(wù):訂單服務(wù)(order),本金服務(wù)(capital)和紅包服務(wù)(redPacket)。主調(diào)方是Order,被調(diào)方Capital和RedPacket.

下面是絞盡腦汁畫的調(diào)用流程圖,為了圖的簡便直觀,省去了cancel的處理,只有try和confirm的調(diào)用(cancel的處理和confirm基本一致)。紅線是try的調(diào)用,藍(lán)線是confirm的調(diào)用。粗紅線是開始,粗藍(lán)線是結(jié)束。
在try階段的makePayment,方法調(diào)用了兩個子事務(wù)的api方法,其他的方法的調(diào)用均是全局事務(wù)切面決定的。業(yè)務(wù)方法只要按TCC框架的要求實現(xiàn)即可,其他的交給TCC框架。

主要代碼分析

我們從TCC事務(wù)注解開始,先介紹幾個基本的類。

/**
屬性主要是事務(wù)傳播屬性,提交方法,回滾方法,上下文傳遞類,是否異步提交,是否異步回滾
propagation屬性比較重要,值有required,support,mandatory和requireNEW,具體的含義和spring的事務(wù)傳播類似。
**/
public @interface Compensable {
    public Propagation propagation() default Propagation.REQUIRED;
    public String confirmMethod() default "";
    public String cancelMethod() default "";
    public Class transactionContextEditor() default DefaultTransactionContextEditor.class;
    public boolean asyncConfirm() default false;
    public boolean asyncCancel() default false;
/**
事務(wù)狀態(tài),在TCC的不通階段進(jìn)行事務(wù)狀態(tài)的變更。
**/
public enum TransactionStatus {
    TRYING(1), CONFIRMING(2), CANCELLING(3);
/**
    ROOT:事務(wù)啟動方法,比如例子中order的makePayment方法
    PROVIDER:事務(wù)協(xié)同方法,比如例子中redpacket的record方法
    Normal:普通方法,比如API里面的record方法
**/
public enum  MethodType {
    ROOT, PROVIDER, NORMAL;
}
/**
    ROOT:主事務(wù),一般MethodType為ROOT的啟動
    BRANCH:分支事務(wù)
**/
public enum TransactionType {
    ROOT(1),
    BRANCH(2);

下面我們看一下事務(wù)持久的內(nèi)容,能更好的幫助理解。每個服務(wù)都會有一張事務(wù)表,會記錄所有的ROOT和BRANCH事務(wù),在事務(wù)完成之后,會自動刪除。

TRANSACTION_ID DOMAIN GLOBAL_TX_ID BRANCH_QUALIFIER CONTENT STATUS TRANSACTION_TYPE RETRIED_COUNT VERSION
2 ORDER 事務(wù)編號001 分支標(biāo)識A 事務(wù)對象A 2 1 0 11
2 CAPITAL 事務(wù)編號001 分支標(biāo)識B 事務(wù)對象B 2 2 0 11
2 REDPACKET 事務(wù)編號001 分支標(biāo)識C 事務(wù)對象C 2 2 0 11
domain區(qū)分了服務(wù)
global_tx_id 串起了所有的事務(wù)
transaction_type 1為主事務(wù),2為分支事務(wù)
content 用于恢復(fù)事務(wù),主事務(wù)的content中包含了參與者

代碼部分的最后是兩個切面和恢復(fù)的job,不進(jìn)行特別的解釋了,將我的理解放在代碼的注釋里面。

    //CompensableTransactionInterceptor.java
    public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
        //獲取所執(zhí)行事務(wù)方法的設(shè)置屬性
        Method method = CompensableMethodUtils.getCompensableMethod(pjp);
        Compensable compensable = method.getAnnotation(Compensable.class);
        Propagation propagation = compensable.propagation();
        TransactionContext transactionContext = FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs());
        boolean asyncConfirm = compensable.asyncConfirm();
        boolean asyncCancel = compensable.asyncCancel();
        
        //當(dāng)前是否存在事務(wù),
        boolean isTransactionActive = transactionManager.isTransactionActive();

        /**
         * 判斷方法類型
         * MethodType一共有三種,Root,Provider,Normal. 主要通過propagation和isTransactionActive來確定
         */
        MethodType methodType = CompensableMethodUtils.calculateMethodType(propagation, isTransactionActive, transactionContext);
        switch (methodType) {
            case ROOT:
            //ROOT:(1)propagation為require_new (2)propataion為require,且之前沒有有事務(wù)存在
            //主事務(wù)處理方法
                return rootMethodProceed(pjp, asyncConfirm, asyncCancel);
            case PROVIDER:
            //PROVIDER:(1) propation為require或者mandatory,且之前有事務(wù)
            //從事務(wù)處理方法
                return providerMethodProceed(pjp, transactionContext, asyncConfirm, asyncCancel);
            default:
                //普通方法執(zhí)行
                return pjp.proceed();
        }
    }
    
    private Object rootMethodProceed(ProceedingJoinPoint pjp, boolean asyncConfirm, boolean asyncCancel) throws Throwable {
        Object returnValue = null;
        Transaction transaction = null;
        try {
            //開啟新的主事務(wù),使用新生成的xid,狀態(tài)為trying,事務(wù)類型為ROOT
            transaction = transactionManager.begin();
            try {
                returnValue = pjp.proceed();
            } catch (Throwable tryingException) {
                if (!isDelayCancelException(tryingException)) {
                    logger.warn(String.format("compensable transaction trying failed. transaction content:%s", JSON.toJSONString(transaction)), tryingException);
                    //異常回滾,將事務(wù)狀態(tài)更新為CANCELLING
                    transactionManager.rollback(asyncCancel);
                }
                throw tryingException;
            }
            //執(zhí)行confirm方法,將事務(wù)狀態(tài)更新為CONFIRMING。如果是異步,則TM會使用線程池異步執(zhí)行,否則直接調(diào)用,會協(xié)調(diào)所有的參與者進(jìn)行提交。并將事務(wù)記錄刪除
            transactionManager.commit(asyncConfirm);
        } finally {
            //清理事務(wù)數(shù)據(jù)
           transactionManager.cleanAfterCompletion(transaction);
        }
        return returnValue;
    }

    private Object providerMethodProceed(ProceedingJoinPoint pjp, TransactionContext transactionContext, boolean asyncConfirm, boolean asyncCancel) throws Throwable {
        Transaction transaction = null;
        try {
            switch (TransactionStatus.valueOf(transactionContext.getStatus())) {
                case TRYING:
                    //開啟一個子事務(wù),并調(diào)用TCC的try方法
                    transaction = transactionManager.propagationNewBegin(transactionContext);
                    return pjp.proceed();
                case CONFIRMING:
                    //獲取子事務(wù)TRY階段的事務(wù),并調(diào)用TCC的commit方法
                    try {
                        transaction = transactionManager.propagationExistBegin(transactionContext);
                          transactionManager.commit(asyncConfirm);
                    } catch (NoExistedTransactionException excepton) {
                        //the transaction has been commit,ignore it.
                    }
                    break;
                case CANCELLING:
                    //獲取子事務(wù)保存的事務(wù)數(shù)據(jù),執(zhí)行cancel方法
                    
                    try {
                        transaction = transactionManager.propagationExistBegin(transactionContext);
                        transactionManager.rollback(asyncCancel);
                    } catch (NoExistedTransactionException exception) {
                        //the transaction has been rollback,ignore it.
                    }
                    break;
            }

        } finally {
            //清理事務(wù)數(shù)據(jù)
           transactionManager.cleanAfterCompletion(transaction);
        }
        Method method = ((MethodSignature) (pjp.getSignature())).getMethod();

        return ReflectionUtils.getNullValue(method.getReturnType());
    }

    private boolean isDelayCancelException(Throwable throwable) {

        if (delayCancelExceptions != null) {
            for (Class delayCancelException : delayCancelExceptions) {

                Throwable rootCause = ExceptionUtils.getRootCause(throwable);

                if (delayCancelException.isAssignableFrom(throwable.getClass())
                        || (rootCause != null && delayCancelException.isAssignableFrom(rootCause.getClass()))) {
                    return true;
                }
            }
        }

        return false;
    }
總結(jié)

代碼分析的比較少,這份代碼還是有很多值得稱道的地方,工廠類,緩存,模板方法等設(shè)計模式的使用,下次可以從設(shè)計模式的角度來進(jìn)行分析。除了TCC,最近項目中還涉及了安全消息,等弄清楚了再來一發(fā)。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/74067.html

相關(guān)文章

  • 分布式事務(wù)中間件Seata的設(shè)計原理

    摘要:如上圖所示,的實際上是已中間件的形式放在應(yīng)用層,不用依賴數(shù)據(jù)庫對協(xié)議的支持,完全剝離了分布式事務(wù)方案對數(shù)據(jù)庫在協(xié)議支持上的要求。 微信公眾號「后端進(jìn)階」,專注后端技術(shù)分享:Java、Golang、WEB框架、分布式中間件、服務(wù)治理等等。 在微服務(wù)架構(gòu)體系下,我們可以按照業(yè)務(wù)模塊分層設(shè)計,單獨部署,減輕了服務(wù)部署壓力,也解耦了業(yè)務(wù)的耦合,避免了應(yīng)用逐漸變成一個龐然怪物,從而可以輕松擴(kuò)展,...

    Kylin_Mountain 評論0 收藏0
  • 干貨:分布式系統(tǒng)學(xué)習(xí)筆記

    摘要:即服務(wù)不能無響應(yīng),或出錯分區(qū)的容忍性,這里的分區(qū)不是指數(shù)據(jù)分布式存儲中的分區(qū)。假設(shè)一個分布式系統(tǒng)中,有兩個節(jié)點,處于分區(qū)狀態(tài)。在大多數(shù)的分布式系統(tǒng)設(shè)計中,人們多會選擇滿足兩點特性。為了解決最終的一致性,這就涉及到分布式事務(wù)。 showImg(https://segmentfault.com/img/bV7kd4?w=500&h=253); 一、分布式的兩大場景 數(shù)據(jù)存儲的分布式 服務(wù)的...

    劉德剛 評論0 收藏0
  • 干貨:分布式系統(tǒng)學(xué)習(xí)筆記

    摘要:即服務(wù)不能無響應(yīng),或出錯分區(qū)的容忍性,這里的分區(qū)不是指數(shù)據(jù)分布式存儲中的分區(qū)。假設(shè)一個分布式系統(tǒng)中,有兩個節(jié)點,處于分區(qū)狀態(tài)。在大多數(shù)的分布式系統(tǒng)設(shè)計中,人們多會選擇滿足兩點特性。為了解決最終的一致性,這就涉及到分布式事務(wù)。 showImg(https://segmentfault.com/img/bV7kd4?w=500&h=253); 一、分布式的兩大場景 數(shù)據(jù)存儲的分布式 服務(wù)的...

    EsgynChina 評論0 收藏0
  • Spring Cloud 分布式事務(wù)管理

    摘要:中大致分為兩部分事務(wù)管理器和本地資源管理器。具體實現(xiàn)分布式事務(wù)框架的核心功能是對本地事務(wù)的協(xié)調(diào)控制,框架本身并不創(chuàng)建事務(wù),只是對本地事務(wù)做協(xié)調(diào)控制。 Spring Cloud 分布式事務(wù)管理 在微服務(wù)如火如荼的情況下,越來越多的項目開始嘗試改造成微服務(wù)架構(gòu),微服務(wù)即帶來了項目開發(fā)的方便性,又提高了運(yùn)維難度以及網(wǎng)絡(luò)不可靠的概率. @[toc]在說微服務(wù)的優(yōu)缺點時,有對比才會更加明顯,首先...

    aboutU 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<