系列目錄
一、引子
事務(數據庫事務)是java開發工程師必須掌握的一項技能。又可分為本地事務和分布式事務,其中分布式事務是進階為高級開發工程師必會的技能。本文從概念、原理、實踐多角度剖析分布式事務,希望有所收獲。
二、概念
2.1.本地事務
大部分情況下,一個服務操作一個數據庫,這就是本地事務,ACID特性由數據庫提供支持,比如mysql innodb引擎。如下圖所示(網上的圖,挺好直接用):
spring 提供了2種方式實現:
- 編程式:基於transactionTemplate去實現,適合手動精准控制事務的場景,少用。
- 聲明式事務注解:@Transactional加在serviceImpl的方法上即可,這也是常用的方法。
關於本地事務這里不多說,飛機票:本地事務飛機票。
2.2.分布式事務
當遇到復雜業務調用時,可能會出現跨庫多資源調用(一個事務管理器,多個資源)/多服務調用(多個事務管理器,多個資源),期望全部成功或失敗回滾,這就是分布式事務,用以保證“操作多個隔離資源的數據一致性”。
2.3 相關協議發展歷史
三、DTP模型 & XA規范
背景
Mysql官方對於XA事務,描述如下:
- Mysql InnoDB引擎支持分布式事務,mysql的XA實現是基於X/Open CAE 文檔中的 Distributed Transaction Processing: The XA Specification. (DTP XA規范)的。飛機票:13.3.7 XA Transactions官方飛機票。X/Open CAE解釋如下:
- X/Open: X/Open是一個獨立的、全球性的開放系統組織,由世界上最大的信息系統供應商、用戶組織和軟件公司支持。其使命是通過開放系統的實際實施,為用戶帶來更大的計算價值。
- X/Open CAE規范: 即X/Open Common Applications Environment,這個環境覆蓋了高於硬件級別的,支持開放系統所需的一組標准。它提供了應用程序的可移植性和互操作性。
- MySQL Connector 5.0.0及更高版本直接支持XA,通過一個類接口為您處理XA SQL語句接口。XA支持分布式事務,即允許多個單獨的事務資源參與全局事務。事務資源通常是rdbms,但也可能是其他類型的資源。
- X/Open CAE文檔是發布在open group官網上的,http://www.opengroup.org/public/pubs/catalog/c193.htm。
在open group官網可查到,有2個XA規范,一個是XA,一個是XA+, 其中XA+是XA的超集,新定義了通信資源管理器CRM的協議,建議直接看XA+即可。后續分析直接以XA+ 1994版為准。官方下載鏈接如下:
- 分布式事務處理:參考模型 Distributed Transaction Processing: Reference Model
- 分布式事務處理:XA+規范 Distributed Transaction Processing:The XA+ Specification
看名字我們就知道 XA規范是依托於DTP場景的,下面我們分別從DTP模型、XA規范2個視角來剖析原理。
3.1 DTP模型
依據X/Open《Distributed Transaction Processing: Reference Model, Version 3》上的介紹,DTP模型是一種軟件體系結構,它允許多個應用程序共享多個資源管理器提供的資源,並允許將它們的工作協調到全局事務中。
3.1.1 模型元素
要深度了解DTP,先看看模型內的元素概念,如下:
- 應用程序(Application Program ,簡稱AP):每個AP指定一個包含資源(如數據庫)的操作序列。AP定義全局事務的開始和結束,訪問事務邊界內的資源,通常決定是提交還是回滾每個事務。
- 資源管理器(Resource Manager,簡稱RM):如數據庫、文件系統等,並提供訪問資源的方式。
- 事務管理器(Transaction Manager ,簡稱TM):管理全局事務,負責分配事務唯一標識XID,監控事務的執行進度,並負責事務的提交、回滾等。如果RM是一個通信資源管理器(CRM),那么在執行兩個APs之間的通信時,它將xid傳遞給合作伙伴、從屬的CRMs。
- 通信資源管理器(Communication Resource Manager,簡稱CRM):控制一個TM域(TM domain)內或者跨TM域的分布式應用之間的通信。
- 通信協議(Communication Protocol,簡稱CP):一種通信協議,它提供分布式應用程序使用的、由CRMs支持的底層通信服務。
介紹完模型元素,下面來看2種典型的DTP場景,一種是單應用跨庫DTP,另一種是跨應用DTP。
3.1.2 單應用跨庫DTP
一個應用使用一個事務管理器TM,操作多個資源管理器RMs,如下圖:
3.1.3 跨應用DTP
如果分布式事務需要跨多個應用,例如微服務調用,那就必須增加通訊資源管理器CRMs(跨應用管理事務),如下圖:
上圖中使用的接口如下:
- AP-RM接口 : 允許AP訪問資源,如SQL和ISAM,提供AP可移植性。
- AP-TM接口 : 即TX接口,為AP提供了一個API, AP通過API與TM協調全局事務管理。
- TM-RM接口 : 即XA接口,允許TM將RMs的工作構造為全局事務,並協調完成或恢復。XA接口是TM與RM之間的雙向接口。
- TM-CRM接口 : 即XA+接口,支持跨TM域的全局事務信息流。XA+ 接口是TM與CRM之間的雙向接口。
- AP-CRM接口 : 為全局事務中的多應用之間的DTP通信提供了可移植的api,例如:TxRPC、XATMI、Peer-to-Peer。
- CRM-OSI TP接口 : 即XAP-TP接口,提供了CRM和OSITP(Open Systems Interconnection — Distributed Transaction Processing)服務之間的編程接口。X/Open定義了這個接口來支持特定於應用程序的OSI服務的可移植實現。
本節我們剖析了DTP模型,以及XA接口在DTP中的作用,下面我們來更詳細的看一下XA規范。
3.2 XA規范
通過上面的分析,我們知道XA和XA+規范的使用場景,如下圖所示:
下面來具體看一下XA/XA+接口定義的函數群。其中帶+號的是XA+規范,不帶+號的是XA規范。
3.2.1 xa_*()函數群
TM通過xa_*()函數調用RM。當AP調用TM啟動全局事務時,TM可以使用xa_interface通知事務分支的RMs。AP使用RM的本機接口完成支持全局事務的工作后,TM調用xa_()函數提交或回滾分支。xa_()函數如下表所示:
3.2.2 ax_*()函數群
RM通過ax_*()函數調用TM。所有的TMs都必須提供這些功能。這些函數允許RM動態地控制它在事務分支中的參與。此外,CRMs使用ax_interface創建事務分支,掛起或完成事務分支,並將承諾協議傳播到事務分支。ax_()函數如下表所示:
關於XA/XA+的具體方法如何調用流程這里就不再提供。有興趣的自己看規范原文。
3.3 兩階段提交-2PC
XA協議中有一個細節:按照OSITP標准(模型)的定義,TMs和RMs使用兩階段提交全局事務。
3.3.1 XA的兩階段提交模型
如上圖,XA規范實現的兩階段提交流程:(下面全部翻譯自XA規范原文)
階段1:
TM要求所有RMs准備提交(或准備)事務分支。這詢問RM是否能夠保證提交事務分支的能力。RM可能會查詢該RM內部的其他實例。CRM被要求准備它們創建的事務分支,將prepare請求發送到遠程站點並接收結果。在返回失敗並回滾其工作之后,RM可以丟棄事務分支的信息。
階段2:
TM根據實際情況向所有RMs發出提交或回滾事務分支的請求。CRM被要求提交或回滾它們創建的事務分支,向遠程站點發送提交或回滾請求並接收結果。所有RMs提交或回滾對共享資源的更改,然后將狀態返回給TM。然后TM可以丟棄全局事務的信息。
3.3.2 XA對2PC的優化
1.只讀斷言
當事務分支沒有更新共享資源時,這個RM會斷言並響應給TM的prepare請求。也就免去了階段2。但是,如果一個RM在全局事務的所有RMs返回prepared之前返回了只讀優化,該RM釋放事務上下文,例如read locks。這時候其他事務就有機會去改變這些數據(可能是寫鎖),顯然全局序列化被破壞。同樣CRM也可以斷言,當TM掛起或終止線程與事務分支的關聯時,它不是某個特定線程中活動的事務分支的參與者。
2.一階段提交
如果一個TM知道DTP系統中只有一個RM在修改共享資源,那么它可以使用單階段提交。即TM免去了階段1的prepare,直接執行了階段2的commit。
3.3.3 2PC的缺點
1.資源阻塞
由於協調者的重要性,一旦協調者TM發生故障。參與者RM會一直阻塞下去。尤其在第二階段,協調者發生故障,那么所有的參與者還都處於鎖定事務資源的狀態中,而無法繼續完成事務操作。(如果是協調者掛掉,可以重新選舉一個協調者,但是無法解決因為協調者宕機導致的參與者處於阻塞狀態的問題)
2.數據不一致
在階段二,當協調者向參與者發送commit請求之后,發生了局部網絡異常或者在發送commit請求過程中協調者發生了故障,導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之后就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是整個分布式系統便出現了數據不一致性的現象。
由於二階段提交存在着這些缺陷,所以,研究者們在二階段提交的基礎上做了改進,提出了三階段提交。
3.4 三階段提交-3PC
3PC,即Three-phase commit protocol,由一個協調者領導事務(領頭人),和一組被指導的參與者(同伙)組成。協調者和參與者都有超時執行機制,如下圖:
階段1:
【協調者】接收事務請求。如果此時出現故障,協調者將中止事務,否則,協調者發送一個canCommit給所有參與者,並切換到waiting狀態。
【參與者】獲得了canCommit的請求,如果同意,它將向協調者發送Yes消息並切換到prepared狀態。否則它將發送No消息並中止。如果出現故障,它將移動到abort狀態。
階段2:
【協調者】在一個時間段內,接收來自所有參與者的Yes消息,向所有參與者發送preCommit消息並切換到prepared狀態。如果出現故障、超時或協調者(prepared狀態)接收到No消息,將中止事務並向所有參與者發送abort消息。
【參與者】收到preCommit消息,它將發送ACK消息並等待最后的提交或中止。如果接收到中止消息、失敗或等待提交的超時,它將中止。
階段3:
【協調者】在收到來自大多數參與者的確認的情況下,協調者切換到commit狀態。並向所有參與者發送doCommit請求。如果協調者在等待一個參與者的ack時超時了,它將中止事務。
【參與者】參與者接收到doCommit請求之后,執行正式的事務提交,並發送ack給協調者。注:超時未收到消息,一樣會提交事務!!!!
3.5 總結
上面講解了2pc、xa、3pc,比較如下:
協議/優缺點 | 優點 | 缺點 |
2PC | 邏輯簡單,容易理解。 | 1.全程阻塞。例如:TM故障,RM阻塞資源。 2.網絡故障時,部分commit,數據一致性無法保證。 |
XA(提交時使用2PC規范) | 1.只讀斷言 2.可進化為一階段提交 |
全局序列化被破壞。臟讀問題。 |
3PC | 引入雙邊超時機制,避免阻塞。 |
1.需要3次請求返回,可能會有長延遲,性能低。 2.基於失敗-停止(fail-stop)模型,出現網絡問題,無法恢復。 |
問題:
上面3種協議都無法解決分布式系統下的數據一致性問題,只有Paxos算法,才能徹底解決該問題。paxos飛機票:底層算法系列:Paxos算法。具體實踐中,為了提高可用性(性能)一般很少做到強一致性。且大批的技術先驅們已經總結出了一套理論,讓我們有理可依。
四、CAP理論
2000年7月,Eric Brewer教授在ACM PODC會議上提出CAP猜想。Brewer認為在設計一個大規模的分布式系統時會遇到三個特性:一致性(consistency)、可用性(Availability)、分區容錯(partition-tolerance),而一個分布式系統最多只能滿足其中的2項。2年后,麻省理工學院的Seth Gilbert和Nancy Lynch從理論上證明了CAP。之后,CAP理論正式成為分布式計算領域的公認定理。
1. 一致性(Consistency)
一致性指“all nodes see the same data at the same time”,即更新操作成功並返回客戶端完成后,所有節點在同一時間的數據完全一致,不能存在中間狀態。
強一致性:所有節點在同一時間的數據完全一致,那么稱之為強一致性。
弱一致性:此外,如果允許存在部分數據不一致,那么就稱之為弱一致性。
最終一致性:如果允許存在中間狀態,只要求經過一段時間后,數據最終是一致的,則稱之為最終一致性。
2. 可用性(Availability)
可用性是指系統提供的服務必須一直處於可用的狀態,對於用戶的每一個操作請求總是能夠在有限的時間內返回結果。
3. 分區容錯性(Partition tolerance)
分區容錯的意思是,節點間通信可能失敗,仍然需要能夠保證對外提供滿足一致性和可用性的服務。
4.1 分析
首先我們必須保證P(分區容錯性),才能稱之為一個分布式系統,因此只能在C(一致性)和A(可用性)之間尋求平衡。而前面我們提到的X/Open XA 兩階段提交協議的分布式事務方案,強調的就是一致性。並且由於其阻塞執行效率低,且當網絡出現問題時也無法真正保證數據一致性,實際應用的並不多。而基於BASE理論的柔性事務,強調的是可用性,目前大行其道,大部分互聯網公司采可能會優先采用這種方案。(有的同學問為啥不用paxos?實現過於復雜,且保證了強一致性,想一想也知道性能會有損耗,所以一般也不用!)
五、BASE理論
2008年7月28日,eBay的架構師Dan Pritchett源於對大規模分布式系統的實踐總結,在ACM上發表文章提出BASE理論。文章鏈接:https://queue.acm.org/detail.cfm?id=1394128
BASE理論是對CAP理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用可以采用適合的方式達到最終一致性(Eventual Consistency)。
BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的縮寫。
1. 基本可用(Basically Available)
指分布式系統在出現不可預知故障的時候,允許損失部分可用性。
2. 軟狀態( Soft State)
指允許系統中的數據存在中間狀態,並認為該中間狀態的存在不會影響系統的整體可用性。
3. 最終一致( Eventual Consistency)
強調的是所有的數據更新操作,在經過一段時間的同步之后,最終都能夠達到一個一致的狀態。
BASE理論面向的是大型高可用可擴展的分布式系統,和傳統的事物ACID特性是相反的。通過犧牲強一致性來獲得可用性,允許數據在一段時間內是不一致的,但最終達到一致狀態。實際應用中,會在對數據庫操作進行本地事務(ACID特性)+Eventually consistent最終一致性(BASE理論)結合使用。
那么如何實現分布式環境下數據的最終一致性呢?
六、最終一致性方案(柔性事務)
實踐中,有些高可用場景下,不必要強一致性,只需要最終一致性即可,這在業內稱呼為"柔性事務",也就是最終一致性方案,是遵循BASE理論設計出來的。
6.1 正向冪等重試+反向異步回調(最大努力通知型)
對於某些非核心service,可以采取正向重試機制。比如一個請求超時失敗了,可以再重試請求幾次,一直到接收到成功返回或者達到重試次數為止。注意這里要保證接口的冪等性。即多次調用結果一樣。
很多調用第三方的接口(比如征信接口,耗時比較長),接口是異步回調型。請求方發送請求后,等待第三方異步回調自己的返回結果接口。
這兩種機制都是不可靠的,必要時刻可以兩者相結合使用。如下圖所示:
6.2 可靠消息最終一致(異步確保型)
這里不講解已支持分布式事務的MQ.
可靠消息就是使用獨立的消息服務,使用“預發送機制”把消息提前入庫,業務確定執行完畢,再修改消息狀態為可發送,然后再發送消息給MQ,消費者再消費。
預發送機制
如果先執行業務,再發消息(先發消息再執行業務也不行),入kafka,可能立刻就消費了。本地事務回滾是無法回滾已發送到kafka的消息的。使用預發送機制,保證了消息服務DB中有一條“初始化”狀態的消息記錄。業務異常,就不會“確認發送Msg”,消息就不會發送。
可靠場景下,甚至可以在消息服務中輪詢”初始化“狀態的且過了“一個時間段”(一般超過這個時間,肯定是出問題了)的消息,再去查詢業務系統是否完成,如果完成則自修復成"待發送"狀態。
注:上圖主業務作為生產者,嚴格來說,消息服務平台才是生產者(如果把kafka作為中心的話)。
整個流程如上圖:
- 消息入庫:主業務系統,初始化一條消息進msg表,state=初始化。
- 確認可發送:更新消息狀態state=待發送。
- send生產消息:定時輪詢state=待發送 的消息,send給kafka。
- pull消費消息:從業務作為消費者主動去kafka 拉取消息消費。
- ack告知kafka:消費成功告知kafka。
- 告知消息服務:消費成功告知消息服務,更新狀態state=完成,或者刪除消息記錄。(如果場景要求較高建議留下存根)
本地消息表(業務系統+消息表,強一致性)
如果不使用獨立的消息服務平台,在業務系統內部新建一張消息表,就可以完全由一個本地事務來控制,這樣第1、2步的“消息入庫”、“確認發送”可以確保成功,也就不需要“輪詢自修復”了,如果公司不要求使用統一消息服務平台的話,使用本地消息表也是ok的。
6.3 TCC(兩階段補償型)
TCC 其實就是采用的補償機制,其核心思想是:針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作。TCC 實質上是應用層的2PC(2 PhaseCommit, 兩階段提交),好比把 XA 兩階段提交那種在數據資源層做的事務管理工作提到了數據應用層。TCC流程如下圖:
如上圖所示,步驟:
- 階段1
主業務活動請求(try)各個從業務服務預留資源。try過程的本地事務,是保證資源預留的業務邏輯的正確性。
- 階段2
如果在第一階段所有業務資源都預留成功,那么confirm各個從業務服務,否則取消(cancel)所有從業務服務的資源預留請求。
優點:
相比XA是資源層面的分布式事務,強一致性,在兩階段提交的整個過程中,一直會持有資源的鎖。
TCC是業務層面的分布式事務,最終一致性,不會一直持有資源的鎖。confirm/cancel執行的本地事務邏輯確認/取消預留資源,confirm和cancel就是補償型事務
(Compensation-Based Transactions)。注意:confirm和cancel都是獨立的本地事務,是對try的補償。
缺點:
針對一個請求,需要從業務服務提供3個接口,供主業務服務調用,業務方改造成本高。
====參考=======
分布式事務 :第一節很多都是參考本文,寫的不錯。