解密分佈式事務框架-Fescar

1.分佈式事務

在去年的時候我寫過一篇關於分佈式事務的文章再有人問你分佈式事務,把這篇扔給他。再這篇文章中我叫你們能不用分佈式事務就別用分佈式事務,由於會引入不少的複雜度。當時說這個的時候其實還有一個緣由,沒有大廠的成熟開源解決方案,雖然再網上有不少開源的分佈式事務框架,可是都不是太成熟,沒有大量的業務驗證。它不像其餘的分佈式中間件有大量的成熟的解決方案,好比分佈式消息隊列中間件:Apache Kafka,Apache RocketMQ,Apache Pulsar這三個均是Apache頂級項目;又好比分佈式任務調度,也有不少的開源好比XXL-JOB,Elastic-Job都是有不少的公司在使用。java

而咱們的分佈式事務框架,卻一直沒有一個通過大量業務驗證的框架。經過個人一些瞭解,其實各大公司都是有本身的分佈式事務的解決方案,但不少時候都和業務上強耦合了,不適於作一些通用的框架。可是阿里在今年年初的時候給了你們一個驚喜,Fescar開源!從而讓你們再之後選擇分佈式事務的時候多了一個選擇方案,並且是通過成熟業務驗證的方案。git

這篇文章我會帶你們認識Fescar,以及他的一些設計。後續的文章還會陸續推出Fescar的核心源碼解析篇。github

2.初識Fescar

說Fescar以前這裏先簡單的介紹一下著名的2PC:XA Transactions。 在XA協議中分爲兩階段:  第一階段:事務管理器要求每一個涉及到事務的數據庫預提交(precommit)此操做,並反映是否能夠提交.redis

第二階段:事務協調器要求每一個數據庫提交數據,或者回滾數據。數據庫

優勢: 儘可能保證了數據的強一致,實現成本較低,在各大主流數據庫都有本身實現,對於MySQL是從5.5開始支持。緩存

缺點:網絡

  • 單點問題:事務管理器在整個流程中扮演的角色很關鍵,若是其宕機,好比在第一階段已經完成,在第二階段正準備提交的時候事務管理器宕機,資源管理器就會一直阻塞,致使數據庫沒法使用。
  • 同步阻塞:在準備就緒以後,資源管理器中的資源一直處於阻塞,直到提交完成,釋放資源。
  • 數據不一致:兩階段提交協議雖然爲分佈式數據強一致性所設計,但仍然存在數據不一致性的可能,好比在第二階段中,假設協調者發出了事務commit的通知,可是由於網絡問題該通知僅被一部分參與者所收到並執行了commit操做,其他的參與者則由於沒有收到通知一直處於阻塞狀態,這時候就產生了數據的不一致性。
  • 只能用於單一類型數據庫,跨數據庫種類,其餘緩存或者文件等資源不支持。

總的來講,XA協議比較簡單,成本較低,可是其單點問題,以及不能支持高併發(因爲同步阻塞)依然是其最大的弱點。併發

能夠看見XA協議問題較多因此其做爲分佈式事務方案討論的時候基本都會被無情的幹掉,可是XA有個很好優勢是對業務沒有侵入(數據庫層面),再業務上不須要編寫額外的代碼,更加關注業務。框架

在個人那篇文章中我又介紹了幾種在應用層面上的分佈式事務,可是或多或少的對業務都有必定的入侵。好比咱們的TCC,經常使用的一些TCC框架都須要編寫try,confirm,cancel等接口對於現成的業務須要進行轉換。若是採用本地消息表模式那麼又須要增長額外的表。若是採用事務性消息好比RocketMQ,會讓一些沒有使用該消息隊列的業務須要更換消息隊列。若是採用Saga模式,一樣咱們須要編寫正向和反向接口。能夠看見不論採用哪一種分佈式事務方案,都會有必定的業務改造,業務入侵成本。異步

而Fescar結合了XA的無侵入的優勢和其餘應用層事務協議高性能的優勢,在應用層實現了二階段協議的事務,同時對業務代碼基本無侵入。

2.1 Fescar和XA

Fescar雖然是二階段提交協議的分佈式事務,可是其解決了上面XA的一些缺點:

  • 單點問題:雖然目前Fescar(0.4.1)仍是單server的,可是Fescar官方預計將會在0.5.x中推出HA-Cluster,到時候就能夠解決單點問題。
  • 同步阻塞:Fescar的二階段,其再第一階段的時候本地事務就已經提交釋放資源了,不會像XA會再兩個prepare和commit階段資源都鎖住,而且Fescar,commit是異步操做,也是提高性能的一大關鍵。
  • 數據不一致:若是出現部分commit失敗,那麼fescar-server會根據當前的事務模式和分支事務的返回狀態的結果來進行不一樣的重試策略。而且fescar的本地事務會在一階段的時候進行提交,其實單看數據庫來講在commit的時候數據庫已是一致的了。
  • 只能用於單一數據庫: Fescar提供了兩種模式,AT和MT。在AT模式下事務資源能夠是任何支持ACID的數據庫,在MT模式下事務資源沒有限制,能夠是緩存,能夠是文件,能夠是其餘的等等。固然這兩個模式也能夠混用。

同時Fescar也保留了接近0業務入侵的優勢,只須要簡單的配置Fescar的數據代理和加個註解,加一個Undolog表,就能夠達到咱們想要的目的。

3.Fescar整體設計

Fescar的設計核心就是他的角色分類。不管是數據庫上的XA仍是Fescar都有兩個角色TM(事務管理器)和RM(資源管理器),同時Fescar還有一個TC(事務協調器)。咱們先來看看若是沒有TC,只有TM和RM會發生什麼呢?這裏我舉個簡單的例子,小明去網站上面購買了一個商品,以下圖所示:

這裏小明其實就是TM(事務管理器),而商品和帳戶其實就是咱們的RM(資源管理器),正常狀況下可能沒問什麼問題,帳戶和庫存都能扣減成功。若是小明再扣減庫存的時候成功可是在扣減帳戶的時候失敗,這個時候就須要對咱們的庫存資源進行回滾。小明這個時候就會通知庫存把上個階段扣減的貨物補回來。可是回滾庫存的時候庫存服務不穩定,此次回滾就失敗了。通常來講小明會不斷的去重試,直到成功。這樣就有個問題小明就一直被阻塞,不能作任何事。這個也能夠看作二階段commit/rollback的時候一直會阻塞TM,網易DDB的XA協議針對這種狀況會作一個異步線程的操做。可是在Fescar中一切都是由TC去作的,固然TC其實不只僅會作二階段失敗的重試,他會作二階段的全部RM的commit和rollback,讓咱們的TM作更少的事。

再Fescar中TM,RM,TC的關係以下面官方提供的圖:

  • TM:事務的發起者。用來告訴TC,全局事務的開始,提交,回滾。
  • RM:具體的事務資源,每個RM都會做爲一個分支事務註冊在TC。
  • TC:事務的協調者。也能夠看作是Fescar-servr,用於接收咱們的事務的註冊,提交和回滾。

這三個角色的分工明確,正是咱們Fescar真正的核心所在,下面我會經過如何使用Fescar帶你們更加深入的理解這三個角色。

4.快速開始Fescar

在Fescar的github上已經提供了一個簡單的例子https://github.com/fescar-group/fescar-samples,這裏咱們須要將這個例子下載下來。

4.1搭建TC Fescar-server

首先咱們搭建事務協調器,也能夠叫作搭建Fescar-Server.官網的例子是使用Nacos加上fescar-server已經打好的Jar包運行的。這裏爲了方便咱們直接下載fescar的代碼https://github.com/alibaba/fescar。

找到咱們的Server:

直接運行main方法,該方法會幫助咱們在本地啓動一個端口號爲8091的fescar-server服務。若是咱們想要進行服務註冊,咱們能夠修改registry.conf下面的type

能夠看見在0.4.1版本的時候支持四種服務註冊,nacos,eureka,redis,zk。目前使用redis進行服務註冊是有問題的,我也提了一個PR給官方進行修正。固然爲了方便其實選擇file,後續咱們直連是最爲便捷的。

再運行main方法以後,若是出現Server started日誌,就表明咱們的TC(事務協調器)成功啓動。

4.2 認識TM

上面事務協調器已經搭建完成,咱們接下來須要作的就是將TM和RM運行起來,將對應的操做交給咱們的事務協調器去作。這個時候咱們須要打開fescar-samples這個項目:因爲這個項目使用的RPC是Dubbo,他默認配的服務註冊中心是Nacos,須要咱們再本地安裝一個Nacos,具體安裝能夠自行搜索,這裏不展開講了。

這裏官方例子中,業務關係以下圖: 

能夠看見Business也就是咱們的TM,找到對應的代碼:

從代碼中咱們知道啓動一個分佈式事務是須要添加@GlobalTransactional註解的,固然Fescar也提供了API的方式讓咱們達到一樣的效果。咱們同時也須要修改registry.conf中的Type爲file。

若是不是在例子中,而是在咱們真正的業務上徹底不須要修改業務代碼,直接在咱們分佈式事務發起方添加上這個註解便可。

這個GloablTranscational註解到底作了什麼呢?其實加了這個註解的都會走一個叫GlobalTransactionalInterceptor的切面,再這個切面中又會進入TrascationTemplate這個類中的excute方法,這個也是TM的核心方法:

上面的代碼有部分刪減,只選取了核心的流程。TrascationTemplate其實也是Fescar提供給咱們的API,若是不使用註解那麼咱們也能夠模仿他的方式去作。能夠看見主要分爲五步:

  1. 獲取當前上下文中是否已經有事務,這一步是經過ThreadLocal去實現的,若是有則獲取當前的,若是沒有則獲取默認的。
  2. 開啓事務,這一步是向TC(事務協調器)發出一個請求,註冊一個GloabTranscation,這裏的timeout是指超過這段時間沒有rollback或者commit,TC會幫助咱們作rollback。
  3. 作業務。
  4. 若是該方法拋出了異常,則回滾。這裏要注意的時候拋出異常,不少時候咱們會把異常給捕獲,致使咱們這裏根本沒有異常拋出,因此就不會出現回滾。這裏的回滾也是向TC發起一個回滾請求,由他幫助咱們對RM進行回滾。
  5. 若是沒有異常則向TC發起commit,TC會幫助咱們向RM異步發起提交請求。

TM的核心過程主要是這5步,其餘詳細的講解會在後續的代碼中體現。

4.3 認識RM

當咱們上面的Business發起業務請求以後,就來到了咱們RM的流程,咱們的Storage和Order服務是怎麼知道如今已是處於分佈式事務當中了呢?這個就須要藉助RPC框架來完成了,這裏咱們使用的是Dubbo,fescar爲dubbo提供了一個filter,以下圖所示:

這裏會從rpcContext中獲取咱們的xid,也就是咱們的分佈式事務ID,若是有的話就證實本次請求處於分佈式事務中,那麼就會把XID種入咱們的RootContext(fescar的本地上下文)。若是你不是Dubbo,那麼也能夠根據此方法適配你的RPC。

在RM中咱們應該作什麼呢?只須要作下面兩步:

  1. 將數據源換成Fescar代理 
  2. 在當前數據庫中添加一個Undolog的表,用於記錄日誌回滾。

再Fescar中不只僅是對dataSource進行代理,也會對connection和statement進行代理,以下圖: 

你們都知道咱們的SQL的具體執行須要依賴Statement,在Fescar的StatementProxy中有以下代碼:

能夠看見運行的方法是ExecuteTemplate.execute,在execute方法中會根據咱們執行語句的類型記錄咱們的Undolog,具體的執行流程參考下面官方的一張圖片:

總的來講咱們的RM核心流程主要有兩個:一個是如何識別分佈式事務,另一個是經過咱們數據源代理讓咱們本來簡單的執行SQL流程作了更多的事。

5.總結

寫這篇文章的目的,不只僅是讓你們知道Fescar,也是讓更多的人知道一個優秀分佈式事務框架到底應該怎樣去作。目前Fescar的版本號是0.4.1,還有不少功能好比HA-Cluster,SpringCloud集成尚未發佈。因此目前再線上使用的話可能會遇到Fescar單點的問題,因此目前還不是太推薦線上使用。Fescar的目前規劃會在0.5.x版本推出HA-Cluster,到時候其單點問題就會被解決。

這篇文章的原理目前介紹的比較粗淺,後面會陸續推出三篇文章詳細介紹分析:TC,TM,RM,敬請期待。

最後這篇文章被我收錄於JGrowing-Java分佈式事務篇,一個全面,優秀,由社區一塊兒共建的Java學習路線,若是您想參與開源項目的維護,能夠一塊兒共建,github地址爲:https://github.com/javagrowing/JGrowing 麻煩給個小星星喲。

相關文章
相關標籤/搜索