小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

深度剖析一站式分布式事務(wù)方案 Seata-Server

 airen89 2019-04-12

本文作者:李釗,公眾號(hào)「咖啡拿鐵」作者,分布式事務(wù) Seata 社區(qū) Contributor。

1.關(guān)于 Seata

在前不久,我寫了一篇關(guān)于分布式事務(wù)中間件 Fescar 的解析,沒過幾天 Fescar 團(tuán)隊(duì)對(duì)其進(jìn)行了品牌升級(jí),取名為 Seata(Simpe Extensible Autonomous Transcaction Architecture),而以前的 Fescar 的英文全稱為 Fast & EaSy Commit And Rollback??梢钥匆?Fescar 從名字上來看更加局限于 Commit 和 Rollback,而新的品牌名字 Seata 旨在打造一套一站式分布式事務(wù)解決方案。更換名字之后,我對(duì)其未來的發(fā)展更有信心。

這里先大概回憶一下 Seata 的整個(gè)過程模型:

  • TM:事務(wù)的發(fā)起者。用來告訴 TC,全局事務(wù)的開始,提交,回滾。

  • RM:具體的事務(wù)資源,每一個(gè) RM 都會(huì)作為一個(gè)分支事務(wù)注冊(cè)在 TC。

  • TC 事務(wù)的協(xié)調(diào)者。也可以看做是 Fescar-Server,用于接收我們的事務(wù)的注冊(cè),提交和回滾。

在之前的文章中對(duì)整個(gè)角色有個(gè)大體的介紹,在這篇文章中我將重點(diǎn)介紹其中的核心角色 TC,也就是事務(wù)協(xié)調(diào)器。

2.Transaction Coordinator

為什么之前一直強(qiáng)調(diào) TC 是核心呢?那因?yàn)?TC 這個(gè)角色就好像上帝一樣,管控著蕓蕓眾生的 RM 和 TM。如果 TC 一旦不好使,那么 RM 和 TM 一旦出現(xiàn)小問題,那必定會(huì)亂的一塌糊涂。所以要想了解 Seata,那么必須要了解他的 TC。

那么一個(gè)優(yōu)秀的事務(wù)協(xié)調(diào)者應(yīng)該具備哪些能力呢?我覺得應(yīng)該有以下幾個(gè):

  • 正確的協(xié)調(diào):能正確的協(xié)調(diào) RM 和 TM 接下來應(yīng)該做什么,做錯(cuò)了應(yīng)該怎么辦,做對(duì)了應(yīng)該怎么辦。

  • 高可用:事務(wù)協(xié)調(diào)器在分布式事務(wù)中很重要,如果不能保證高可用,那么他也沒有存在的必要了。

  • 高性能:事務(wù)協(xié)調(diào)器的性能一定要高,如果事務(wù)協(xié)調(diào)器性能有瓶頸,那么他所管理的 RM 和 TM 會(huì)經(jīng)常遇到超時(shí),從而引起回滾頻繁。

  • 高擴(kuò)展性:這個(gè)特點(diǎn)是屬于代碼層面的,如果是一個(gè)優(yōu)秀的框架,那么需要給使用方很多自定義擴(kuò)展,比如服務(wù)注冊(cè)/發(fā)現(xiàn),讀取配置等等。

下面我也將逐步闡述 Seata 是如何做到上面四點(diǎn)。

2.1 Seata-Server 的設(shè)計(jì)

Seata-Server 整體的模塊圖如上所示:

  • Coordinator Core:最下面的模塊是事務(wù)協(xié)調(diào)器核心代碼,主要用來處理事務(wù)協(xié)調(diào)的邏輯,如是否 Commit、Rollback 等協(xié)調(diào)活動(dòng)。

  • Store:存儲(chǔ)模塊,用來將數(shù)據(jù)持久化,防止重啟或者宕機(jī)數(shù)據(jù)丟失。

  • Discover:服務(wù)注冊(cè)/發(fā)現(xiàn)模塊,用于將 Server 地址暴露給 Client。

  • Config:用來存儲(chǔ)和查找服務(wù)端的配置。

  • Lock:鎖模塊,用于給 Seata 提供全局鎖的功能。

  • Rpc:用于和其他端通信。

  • HA-Cluster:高可用集群,目前還沒開源,為 Seata 提供可靠的高可用功能。

2.2 Discover

首先來講講比較基礎(chǔ)的 Discover 模塊,又稱服務(wù)注冊(cè)/發(fā)現(xiàn)模塊。我們將 Seata-Server 啟動(dòng)之后,需要將自己的地址暴露給其他使用者,那么就需要這個(gè)模塊幫忙。

這個(gè)模塊有個(gè)核心接口 RegistryService,如上圖所示:

  • register:服務(wù)端使用,進(jìn)行服務(wù)注冊(cè)。

  • unregister:服務(wù)端使用,一般在 JVM 關(guān)閉鉤子,ShutdownHook 中調(diào)用。

  • subscribe:客戶端使用,注冊(cè)監(jiān)聽事件,用來監(jiān)聽地址的變化。

  • unsubscribe:客戶端使用,取消注冊(cè)監(jiān)聽事件。

  • lookup:客戶端使用,根據(jù) Key 查找服務(wù)地址列表。

  • close:都可以使用,用于關(guān)閉 Register 資源。

如果需要添加自己定義的服務(wù)注冊(cè)/發(fā)現(xiàn),那么實(shí)現(xiàn)這個(gè)接口即可。截止目前在社區(qū)的不斷開發(fā)推動(dòng)下,已經(jīng)有四種服務(wù)注冊(cè)/發(fā)現(xiàn),分別是 redis、zk、nacos、eruka。下面簡(jiǎn)單介紹下 Nacos 的實(shí)現(xiàn):

2.2.1 register 接口

step1:校驗(yàn)地址是否合法;

step2:獲取 Nacos 的 Name 實(shí)例,然后將地址注冊(cè)到當(dāng)前 Cluster 名稱上面。

unregister 接口類似,這里不做詳解。

2.2.2 lookup 接口

step1:獲取當(dāng)前 clusterName 名字;

step2:判斷當(dāng)前 Cluster 是否已經(jīng)獲取過了,如果獲取過就從 Map 中??;

step3:從 Nacos 拿到地址數(shù)據(jù),將其轉(zhuǎn)換成所需要的;

step4:將事件變動(dòng)的 Listener 注冊(cè)到 Nacos。

2.2.3 subscribe 接口

這個(gè)接口比較簡(jiǎn)單,具體分兩步:

step1:將 Clstuer 和 Listener 添加進(jìn) Map 中;

step2:向 Nacos 注冊(cè)。

2.3 Config

配置模塊也是一個(gè)比較基礎(chǔ),比較簡(jiǎn)單的模塊。我們需要配置一些常用的參數(shù)比如:Netty 的 Select 線程數(shù)量,Work 線程數(shù)量,Session 允許最大為多少等等,當(dāng)然這些參數(shù)在 Seata 中都有自己的默認(rèn)設(shè)置。

同樣的在 Seata 中也提供了一個(gè)接口 Configuration,用來自定義需要的獲取配置的地方:

  • getInt/Long/Boolean/Config():通過 DataId 來獲取對(duì)應(yīng)的值。

  • putConfig:用于添加配置。

  • removeConfig:刪除一個(gè)配置。

  • add/remove/get ConfigListener:添加/刪除/獲取 配置監(jiān)聽器,一般用來監(jiān)聽配置的變更。

目前為止有四種方式獲取 Config:File(文件獲?。?、Nacos、Apollo、ZK。在 Seata 中首先需要配置 registry.conf,來配置 conf 的類型。實(shí)現(xiàn) conf 比較簡(jiǎn)單這里就不深入分析。

2.4 Store

存儲(chǔ)層的實(shí)現(xiàn)對(duì)于 Seata 是否高性能,是否可靠非常關(guān)鍵。
如果存儲(chǔ)層沒有實(shí)現(xiàn)好,那么如果發(fā)生宕機(jī),在 TC 中正在進(jìn)行分布式事務(wù)處理的數(shù)據(jù)將會(huì)被丟失。既然使用了分布式事務(wù),那么其肯定不能容忍丟失。如果存儲(chǔ)層實(shí)現(xiàn)好了,但是其性能有很大問題,RM 可能會(huì)發(fā)生頻繁回滾那么其完全無法應(yīng)對(duì)高并發(fā)的場(chǎng)景。

在 Seata 中默認(rèn)提供了文件方式的存儲(chǔ),下面定義存儲(chǔ)的數(shù)據(jù)為 Session,而 TM 創(chuàng)造的全局事務(wù)數(shù)據(jù)叫 GlobalSession,RM 創(chuàng)造的分支事務(wù)叫 BranchSession,一個(gè) GlobalSession 可以擁有多個(gè) BranchSession。我們的目的就是要將這么多 Session 存儲(chǔ)下來。

在 FileTransactionStoreManager#writeSession 代碼中:

上面的代碼主要分為下面幾步:

step1:生成一個(gè) TransactionWriteFuture。

step2:將這個(gè) futureRequest 丟進(jìn)一個(gè) LinkedBlockingQueue 中。為什么需要將所有數(shù)據(jù)都丟進(jìn)隊(duì)列中呢?當(dāng)然這里其實(shí)也可以用鎖來實(shí)現(xiàn),在另外一個(gè)阿里開源的 RocketMQ 中使用的鎖。不論是隊(duì)列還是鎖,他們的目的是為了保證單線程寫,這又是為什么呢?有人會(huì)解釋說,需要保證順序?qū)懀@樣速度就很快,這個(gè)理解是錯(cuò)誤的,我們的 FileChannel 其實(shí)是線程安全的,已經(jīng)能保證順序?qū)懥恕1WC單線程寫其實(shí)是為了讓這個(gè)寫邏輯都是單線程的,因?yàn)榭赡苡行┪募憹M或者記錄寫數(shù)據(jù)位置等等邏輯,當(dāng)然這些邏輯都可以主動(dòng)加鎖去做,但是為了實(shí)現(xiàn)簡(jiǎn)單方便,直接再整個(gè)寫邏輯加鎖是最為合適的。

step3:調(diào)用 future.get,等待該條數(shù)據(jù)寫邏輯完成通知。

我們將數(shù)據(jù)提交到隊(duì)列之后,接下來需要對(duì)其進(jìn)行消費(fèi),代碼如下:

這里將一個(gè) WriteDataFileRunnable() 提交進(jìn)線程池,這個(gè) Runnable 的 run() 方法如下:

分為下面幾步:

step1:判斷是否停止,如果 stopping 為 true 則返回 null。

step2:從隊(duì)列中獲取數(shù)據(jù)。

step3:判斷 future 是否已經(jīng)超時(shí)了,如果超時(shí),則設(shè)置結(jié)果為 false,此時(shí)我們生產(chǎn)者 get() 方法會(huì)接觸阻塞。

step4:將數(shù)據(jù)寫進(jìn)文件,此時(shí)數(shù)據(jù)還在 pageCache 層并沒有刷新到磁盤,如果寫成功然后根據(jù)條件判斷是否進(jìn)行刷盤操作。

step5:當(dāng)寫入數(shù)量到達(dá)一定的時(shí)候,或者寫入時(shí)間到達(dá)一定的時(shí)候,需要將當(dāng)前的文件保存為歷史文件,刪除以前的歷史文件,然后創(chuàng)建新的文件。這一步是為了防止文件無限增長(zhǎng),大量無效數(shù)據(jù)浪費(fèi)磁盤資源。

在 writeDataFile 中有如下代碼:

step1:首先獲取 ByteBuffer,如果超出最大循環(huán) BufferSize 就直接創(chuàng)建一個(gè)新的,否則就使用緩存的 Buffer。這一步可以很大的減少 GC。

step2:然后將數(shù)據(jù)添加進(jìn)入 ByteBuffer。

step3:最后將 ByteBuffer 寫入 fileChannel,這里會(huì)重試三次。此時(shí)的數(shù)據(jù)還在 pageCache 層,受兩方面的影響,OS 有自己的刷新策略,但是這個(gè)業(yè)務(wù)程序不能控制,為了防止宕機(jī)等事件出現(xiàn)造成大量數(shù)據(jù)丟失,所以就需要業(yè)務(wù)自己控制 flush。下面是 flush 的代碼:

這里 flush 的條件寫入一定數(shù)量或者寫的時(shí)間超過一定時(shí)間,這樣也會(huì)有個(gè)小問題如果是停電,那么 pageCache 中有可能還有數(shù)據(jù)并沒有被刷盤,會(huì)導(dǎo)致少量的數(shù)據(jù)丟失。目前還不支持同步模式,也就是每條數(shù)據(jù)都需要做刷盤操作,這樣可以保證每條消息都落盤,但是性能也會(huì)受到極大的影響,當(dāng)然后續(xù)會(huì)不斷的演進(jìn)支持。

Store 核心流程主要是上面幾個(gè)方法,當(dāng)然還有一些比如 Session 重建等,這些比較簡(jiǎn)單,讀者可以自行閱讀。

2.5 Lock

大家知道數(shù)據(jù)庫實(shí)現(xiàn)隔離級(jí)別主要是通過鎖來實(shí)現(xiàn)的,同樣的再分布式事務(wù)框架 Seata 中要實(shí)現(xiàn)隔離級(jí)別也需要通過鎖。一般在數(shù)據(jù)庫中數(shù)據(jù)庫的隔離級(jí)別一共有四種:讀未提交、讀已提交、可重復(fù)讀、串行化。在 Seata 中可以保證寫的互斥,而讀的隔離級(jí)別一般是未提交,但是提供了達(dá)到讀已提交隔離的手段。

Lock 模塊也就是 Seata 實(shí)現(xiàn)隔離級(jí)別的核心模塊。在 Lock 模塊中提供了一個(gè)接口用于管理鎖:

其中有三個(gè)方法:

  • acquireLock:用于對(duì) BranchSession 加鎖,這里雖然是傳的分支事務(wù) Session,實(shí)際上是對(duì)分支事務(wù)的資源加鎖,成功返回 true。

  • isLockable:根據(jù)事務(wù) ID,資源 ID,鎖住的 Key 來查詢是否已經(jīng)加鎖。

  • cleanAllLocks:清除所有的鎖。

對(duì)于鎖我們可以在本地實(shí)現(xiàn),也可以通過 redis 或者 mysql 來幫助我們實(shí)現(xiàn)。官方默認(rèn)提供了本地全局鎖的實(shí)現(xiàn):

在本地鎖的實(shí)現(xiàn)中有兩個(gè)常量需要關(guān)注:

  • BUCKET_PER_TABLE:用來定義每個(gè) table 有多少個(gè) bucket,目的是為了后續(xù)對(duì)同一個(gè)表加鎖的時(shí)候減少競(jìng)爭(zhēng)。

  • LOCK_MAP:這個(gè) Map 從定義上來看非常復(fù)雜,里里外外套了很多層 Map,這里用個(gè)表格具體說明一下:

層數(shù)

key

value

1-LOCK_MAP

resourceId(jdbcUrl)

dbLockMap

2-dbLockMap

tableName (表名)

tableLockMap

3-tableLockMap

PK.hashcode%Bucket (主鍵值的 hashcode%bucket)

bucketLockMap

4-bucketLockMap

PK

trascationId

可以看見實(shí)際上的加鎖在 bucketLockMap 這個(gè) Map 中,這里具體的加鎖方法比較簡(jiǎn)單就不作詳細(xì)闡述,主要是逐步的找到 bucketLockMap ,然后將當(dāng)前 TrascationId 塞進(jìn)去,如果這個(gè)主鍵當(dāng)前有 TranscationId,那么比較是否是自己,如果不是則加鎖失敗。

2.6 RPC

保證 Seata 高性能的關(guān)鍵之一也是使用了 Netty 作為 RPC 框架,采用默認(rèn)配置的線程模型如下圖所示:

如果采用默認(rèn)的基本配置那么會(huì)有一個(gè) Acceptor 線程用于處理客戶端的鏈接,會(huì)有 cpu*2 數(shù)量的 NIO-Thread,再這個(gè)線程中不會(huì)做業(yè)務(wù)太重的事情,只會(huì)做一些速度比較快的事情,比如編解碼,心跳事件和TM注冊(cè)。一些比較費(fèi)時(shí)間的業(yè)務(wù)操作將會(huì)交給業(yè)務(wù)線程池,默認(rèn)情況下業(yè)務(wù)線程池配置為最小線程為 100,最大為 500。

這里需要提一下的是 Seata 的心跳機(jī)制,這里是使用 Netty 的 IdleStateHandler 完成的,如下:

在 Server 端對(duì)于寫沒有設(shè)置最大空閑時(shí)間,對(duì)于讀設(shè)置了最大空閑時(shí)間,默認(rèn)為 15s,如果超過 15s 則會(huì)將鏈接斷開,關(guān)閉資源。

step1:判斷是否是讀空閑的檢測(cè)事件;

step2:如果是,則斷開鏈接,關(guān)閉資源。

2.7 HA-Cluster

目前官方?jīng)]有公布 HA-Cluster,但是通過一些其他中間件和官方的一些透露,可以將 HA-Cluster 用如下方式設(shè)計(jì):

具體的流程如下:

step1:客戶端發(fā)布信息的時(shí)候根據(jù) TranscationId 保證同一個(gè) Transcation 是在同一個(gè) Master 上,通過多個(gè) Master 水平擴(kuò)展,提供并發(fā)處理性能。

step2:在 Server 端中一個(gè) Master 有多個(gè) Slave,Master 中的數(shù)據(jù)近實(shí)時(shí)同步到 Slave上,保證當(dāng) Master 宕機(jī)的時(shí)候,還能有其他 Slave 頂上來可以用。

當(dāng)然上述一切都是猜測(cè),具體的設(shè)計(jì)實(shí)現(xiàn)還得等 0.5 版本之后。目前有一個(gè) Go 版本的 Seata-Server 也捐贈(zèng)給了 Seata (還在流程中),其通過 Raft 實(shí)現(xiàn)副本一致性,其他細(xì)節(jié)不是太清楚。

2.8 Metrics & Tracing

這個(gè)模塊也是一個(gè)沒有具體公布實(shí)現(xiàn)的模塊,當(dāng)然有可能會(huì)提供插件口,讓其他第三方 metric 接入進(jìn)來。另外最近 Apache SkyWalking 正在和 Seata 小組商討如何接入進(jìn)來。

3.Coordinator Core

上面我們講了很多 Server 基礎(chǔ)模塊,想必大家對(duì) Seata 的實(shí)現(xiàn)已經(jīng)有個(gè)大概,接下來我會(huì)講解事務(wù)協(xié)調(diào)器具體邏輯是如何實(shí)現(xiàn)的,讓大家更加了解 Seata 的實(shí)現(xiàn)內(nèi)幕。

3.1 啟動(dòng)流程

啟動(dòng)方法在 Server 類有個(gè) main 方法,定義了我們啟動(dòng)流程:

step1:創(chuàng)建一個(gè) RpcServer,再這個(gè)里面包含了我們網(wǎng)絡(luò)的操作,用 Netty 實(shí)現(xiàn)了服務(wù)端。

step2:解析端口號(hào)和文件地址。

step3:初始化 SessionHolder,其中最重要的重要就是重我們 dataDir 這個(gè)文件夾中恢復(fù)我們的數(shù)據(jù),重建我們的Session。

step4:創(chuàng)建一個(gè)CoorDinator,這個(gè)也是我們事務(wù)協(xié)調(diào)器的邏輯核心代碼,然后將其初始化,其內(nèi)部初始化的邏輯會(huì)創(chuàng)建四個(gè)定時(shí)任務(wù):

  • retryRollbacking:重試 rollback 定時(shí)任務(wù),用于將那些失敗的 rollback 進(jìn)行重試的,每隔 5ms 執(zhí)行一次。

  • retryCommitting:重試 commit 定時(shí)任務(wù),用于將那些失敗的 commit 進(jìn)行重試的,每隔 5ms 執(zhí)行一次。

  • asyncCommitting:異步 commit 定時(shí)任務(wù),用于執(zhí)行異步的 commit,每隔 10ms 一次。

  • timeoutCheck:超時(shí)定時(shí)任務(wù)檢測(cè),用于檢測(cè)超時(shí)的任務(wù),然后執(zhí)行超時(shí)的邏輯,每隔 2ms 執(zhí)行一次。

step5: 初始化 UUIDGenerator 這個(gè)也是我們生成各種 ID(transcationId,branchId) 的基本類。

step6:將本地 IP 和監(jiān)聽端口設(shè)置到 XID 中,初始化 RpcServer 等待客戶端的連接。

啟動(dòng)流程比較簡(jiǎn)單,下面我會(huì)介紹分布式事務(wù)框架中的常見的一些業(yè)務(wù)邏輯 Seata 是如何處理的。

3.2 Begin - 開啟全局事務(wù)

一次分布式事務(wù)的起始點(diǎn)一定是開啟全局事務(wù),首先我們看看全局事務(wù) Seata 是如何實(shí)現(xiàn)的:

step1: 根據(jù)應(yīng)用 ID,事務(wù)分組,名字,超時(shí)時(shí)間創(chuàng)建一個(gè) GlobalSession,這個(gè)再前面也提到過他和 branchSession 分別是什么。

step2:對(duì)其添加一個(gè) RootSessionManager 用于監(jiān)聽一些事件,這里要說一下目前在 Seata 里面有四種類型的 Listener (這里要說明的是所有的 sessionManager 都實(shí)現(xiàn)了 SessionLifecycleListener):

  • ROOTSESSIONMANAGER:最全,最大的,擁有所有的 Session。

  • ASYNCCOMMITTINGSESSION_MANAGER:用于管理需要做異步 commit 的 Session。

  • RETRYCOMMITTINGSESSION_MANAGER:用于管理重試 commit 的 Session。

  • RETRYROLLBACKINGSESSION_MANAGER:用于管理重試回滾的 Session。
    由于這里是開啟事務(wù),其他 SessionManager 不需要關(guān)注,我們只添加 RootSessionManager 即可。

step3:開啟 GlobalSession:

這一步會(huì)把狀態(tài)變?yōu)?Begin,記錄開始時(shí)間,并且調(diào)用 RootSessionManager的 onBegin 監(jiān)聽方法,將 Session 保存到 Map 并寫入到我們的文件。

step4:最后返回 XID,這個(gè) XID 是由 ip+port+transactionId 組成的,非常重要,當(dāng) TM 申請(qǐng)到之后需要將這個(gè) ID 傳到 RM 中,RM 通過 XID 來決定到底應(yīng)該訪問哪一臺(tái) Server。

3.3 BranchRegister - 分支事務(wù)注冊(cè)

當(dāng)全局事務(wù)在 TM 開啟之后,RM 的分支事務(wù)也需要注冊(cè)到全局事務(wù)之上,這里看看是如何處理的:

step1:通過 transactionId 獲取并校驗(yàn)全局事務(wù)是否是開啟狀態(tài)。

step2:創(chuàng)建一個(gè)新的分支事務(wù),也就是 BranchSession。

step3:對(duì)分支事務(wù)進(jìn)行加全局鎖,這里的邏輯就是使用鎖模塊的邏輯。

step4:添加 branchSession,主要是將其添加到 GlobalSession 對(duì)象中,并寫入到我們的文件中。

step5:返回 branchId,這個(gè) ID 也很重要,我們后續(xù)需要用它來回滾我們的事務(wù),或者對(duì)我們分支事務(wù)狀態(tài)更新。

分支事務(wù)注冊(cè)之后,還需要匯報(bào)分支事務(wù)的后續(xù)狀態(tài)到底是成功還是失敗,在 Server 目前只是簡(jiǎn)單的做一下保存記錄,匯報(bào)的目的是,就算這個(gè)分支事務(wù)失敗,如果 TM 還是執(zhí)意要提交全局事務(wù),那么再遍歷提交分支事務(wù)的時(shí)候,這個(gè)失敗的分支事務(wù)就不需要提交。

3.4 GlobalCommit - 全局提交

當(dāng)分支事務(wù)執(zhí)行完成之后,就輪到 TM - 事務(wù)管理器來決定是提交還是回滾,如果是提交,那么就會(huì)走到下面的邏輯:

step1:首先找到 GlobalSession。如果他為 Null 證明已經(jīng)被 Commit 過了,那么直接冪等操作,返回成功。

step2:關(guān)閉  GlobalSession 防止再次有新的 branch 進(jìn)來。

step3:如果 status 是等于 Begin,那么久證明還沒有提交過,改變其狀態(tài)為 Committing 也就是正在提交。

step4:判斷是否是可以異步提交,目前只有AT模式可以異步提交,因?yàn)槭峭ㄟ^ Undolog 的方式去做的。MT 和 TCC 都需要走同步提交的代碼。

step5:如果是異步提交,直接將其放進(jìn) ASYNCCOMMITTINGSESSION_MANAGER,讓其再后臺(tái)線程異步去做  step6,如果是同步的那么直接執(zhí)行 step6。

step6:遍歷 BranchSession 進(jìn)行提交,如果某個(gè)分支事務(wù)失敗,根據(jù)不同的條件來判斷是否進(jìn)行重試,異步不需要重試,因?yàn)槠浔旧矶荚?manager 中,只要沒有成功就不會(huì)被刪除會(huì)一直重試,如果是同步提交的會(huì)放進(jìn)異步重試隊(duì)列進(jìn)行重試。

3.5 GlobalRollback - 全局回滾

如果 TM 決定全局回滾,那么會(huì)走到下面的邏輯:

這個(gè)邏輯和提交流程基本一致,可以看作是他的反向,這里就不展開講了。

4.總結(jié)

最后再總結(jié)一下開始我們提出了分布式事務(wù)的關(guān)鍵四點(diǎn),Seata 到底是怎么解決的:

  • 正確的協(xié)調(diào):通過后臺(tái)定時(shí)任務(wù)各種正確的重試,并且未來會(huì)推出監(jiān)控平臺(tái)有可能可以手動(dòng)回滾。

  • 高可用: 通過 HA-Cluster 保證高可用。

  • 高性能:文件順序?qū)?,RPC 通過 Netty 實(shí)現(xiàn),Seata 未來可以水平擴(kuò)展,提高處理性能。

  • 高擴(kuò)展性:提供給用戶可以自由實(shí)現(xiàn)的地方,比如配置,服務(wù)發(fā)現(xiàn)和注冊(cè),全局鎖等等。

最后希望大家能從這篇文章能了解 Seata-Server 的核心設(shè)計(jì)原理,當(dāng)然你也可以想象如果你自己去實(shí)現(xiàn)一個(gè)分布式事務(wù)的 Server 應(yīng)該怎樣去設(shè)計(jì)?

文中涉及的相關(guān)鏈接

  • Seata github 地址:

    https://github.com/seata/seata

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多