分布式事务原理
一、基礎理論
在講解具體方案之前,我們有必要了解一些分布式事務所涉及到的基礎理論知識。
事務
事務是應用程序中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要么全部成功,要么一個都不做。事務應該具有 4 個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為 ACID 特性。
分布式事務
分布式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位于不同的分布式系統的不同節點之上。例如在大型電商系統中,下單接口通常會扣減庫存、減去優惠、生成訂單 id, 而訂單服務與庫存、優惠、訂單 id 都是不同的服務,下單接口的成功與否,不僅取決于本地的 db 操作,而且依賴第三方系統的結果,這時候分布式事務就保證這些操作要么全部成功,要么全部失敗。本質上來說,分布式事務就是為了保證不同數據庫的數據一致性。
強一致性、弱一致性、最終一致性
-
強一致性 任何一次讀都能讀到某個數據的最近一次寫的數據。系統中的所有進程,看到的操作順序,都和全局時鐘下的順序一致。簡言之,在任意時刻,所有節點中的數據是一樣的。
-
弱一致性 數據更新后,如果能容忍后續的訪問只能訪問到部分或者全部訪問不到,則是弱一致性。
-
最終一致性
不保證在任意時刻任意節點上的同一份數據都是相同的,但是隨著時間的遷移,不同節點上的同一份數據總是在向趨同的方向變化。簡單說,就是在一段時間后,節點間的數據會最終達到一致狀態。
CAP 原則又稱 CAP 定理,指的是在一個分布式系統中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),三者不可得兼。
- 一致性(C): 在分布式系統中的所有數據備份,在同一時刻是否同樣的值。(等同于所有節點訪問同一份最新的數據副本)
- 可用性(A):在集群中一部分節點故障后,集群整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
- 分區容錯性(P):以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在 C 和 A 之間做出選擇。
CAP 原則的精髓就是要么 AP,要么 CP,要么 AC,但是不存在 CAP。如果在某個分布式系統中數據無副本, 那么系統必然滿足強一致性條件, 因為只有獨一數據,不會出現數據不一致的情況,此時 C 和 P 兩要素具備,但是如果系統發生了網絡分區狀況或者宕機,必然導致某些數據不可以訪問,此時可用性條件就不能被滿足,即在此情況下獲得了 CP 系統,但是 CAP 不可同時滿足。
二、BASE 理論
BASE 理論指的是基本可用 Basically Available,軟狀態 Soft State,最終一致性 Eventual Consistency,核心思想是即便無法做到強一致性,但應該采用適合的方式保證最終一致性。
BASE,Basically Available Soft State Eventual Consistency 的簡寫:
- BA:Basically Available 基本可用,分布式系統在出現故障的時候,允許損失部分可用性,即保證核心可用。
- S:SoftState 軟狀態,允許系統存在中間狀態,而該中間狀態不會影響系統整體可用性。
- E:Consistency最終一致性,系統中的所有數據副本經過一定時間后,最終能夠達到一致的狀態。
BASE 理論本質上是對 CAP 理論的延伸,是對 CAP 中 AP 方案的一個補充。
三、柔性事務
不同于 ACID 的剛性事務,在分布式場景下基于 BASE 理論,就出現了柔性事務的概念。要想通過柔性事務來達到最終的一致性,就需要依賴于一些特性,這些特性在具體的方案中不一定都要滿足,因為不同的方案要求不一樣;但是都不滿足的話,是不可能做柔性事務的。
四、冪等操作
在編程中一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函數,或冪等方法,是指可以使用相同參數重復執行,并能獲得相同結果的函數。這些函數不會影響系統狀態,也不用擔心重復執行會對系統造成改變。例如,支付流程中第三方支付系統告知系統中某個訂單支付成功,接收該支付回調接口在網絡正常的情況下無論操作多少次都應該返回成功。
五、分布式事務使用場景
轉賬
轉賬是最經典那的分布式事務場景,假設用戶 A 使用銀行 app 發起一筆跨行轉賬給用戶 B,銀行系統首先扣掉用戶 A 的錢,然后增加用戶 B 賬戶中的余額。此時就會出現 2 種異常情況:1. 用戶 A 的賬戶扣款成功,用戶 B 賬戶余額增加失敗 2. 用戶 A 賬戶扣款失敗,用戶 B 賬戶余額增加成功。對于銀行系統來說,以上 2 種情況都是不允許發生,此時就需要分布式事務來保證轉賬操作的成功。
下單扣庫存
在電商系統中,下單是用戶最常見操作。在下單接口中必定會涉及生成訂單 id, 扣減庫存等操作,對于微服務架構系統,訂單 id 與庫存服務一般都是獨立的服務,此時就需要分布式事務來保證整個下單接口的成功。
同步超時
繼續以電商系統為例,在微服務體系架構下,我們的支付與訂單都是作為單獨的系統存在。訂單的支付狀態依賴支付系統的通知,假設一個場景:我們的支付系統收到來自第三方支付的通知,告知某個訂單支付成功,接收通知接口需要同步調用訂單服務變更訂單狀態接口,更新訂單狀態為成功。流程圖如下,從圖中可以看出有兩次調用,第三方支付調用支付服務,以及支付服務調用訂單服務,這兩步調用都可能出現調用超時的情況,此處如果沒有分布式事務的保證,就會出現用戶訂單實際支付情況與最終用戶看到的訂單支付情況不一致的情況。
六、分布式事務的解決方案
兩階段提交,顧名思義就是要分兩步提交。存在一個負責協調各個本地資源管理器的事務管理器,本地資源管理器一般是由數據庫實現,事務管理器在第一階段的時候詢問各個資源管理器是否都就緒?如果收到每個資源的回復都是 yes,則在第二階段提交事務,如果其中任意一個資源的回復是 no, 則回滾事務。
大致的流程:
- 第一階段(prepare):事務管理器向所有本地資源管理器發起請求,詢問是否是 ready
狀態,所有參與者都將本事務能否成功的信息反饋發給協調者; - 第二階段(commit/rollback):事務管理器根據所有本地資源管理器的反饋,通知所有本地資源管理器,步調一致地在所有分支上提交或者回滾。
存在的問題:
-
同步阻塞:當參與事務者存在占用公共資源的情況,其中一個占用了資源,其他事務參與者就只能阻塞等待資源釋放,處于阻塞狀態。
-
單點故障:一旦事務管理器出現故障,整個系統不可用 數據不一致:在階段二,如果事務管理器只發送了部分 commit 消息,此時網絡發生異常,那么只有部分參與者接收到 commit 消息,也就是說只有部分參與者提交了事務,使得系統數據不一致。
-
不確定性:當協事務管理器發送 commit 之后,并且此時只有一個參與者收到了
commit,那么當該參與者與事務管理器同時宕機之后,重新選舉的事務管理器無法確定該條消息是否提交成功。
關于 TCC(Try-Confirm-Cancel)的概念,最早是由 Pat Helland 于 2007 年發表的一篇名為《Life beyond Distributed Transactions:an Apostate’s Opinion》的論文提出。 TCC 事務機制相比于上面介紹的 XA,解決了其幾個缺點:
- Try 階段:嘗試執行,完成所有業務檢查(一致性), 預留必須業務資源(準隔離性)
- Confirm 階段:確認執行真正執行業務,不作任何業務檢查,只使用 Try 階段預留的業務資源,Confirm
操作滿足冪等性。要求具備冪等設計,Confirm 失敗后需要進行重試。 - Cancel 階段:取消執行,釋放 Try 階段預留的業務資源Cancel 操作滿足冪等性 Cancel 階段的異常和 Confirm 階段異常處理方案基本上一致。
在 Try 階段,是對業務系統進行檢查及資源預覽,比如訂單和存儲操作,需要檢查庫存剩余數量是否夠用,并進行預留,預留操作的話就是新建一個可用庫存數量字段,Try 階段操作是對這個可用庫存數量進行操作。基于 TCC 實現分布式事務,會將原來只需要一個接口就可以實現的邏輯拆分為 Try、Confirm、Cancel 三個接口,所以代碼實現復雜度相對較高。
本地消息表這個方案最初是 ebay 架構師 Dan Pritchett 在 2008 年發表給 ACM 的文章。該方案中會有消息生產者與消費者兩個角色,假設系統 A 是消息生產者,系統 B 是消息消費者,其大致流程如下:
本地消息表實現的條件:
容錯機制:
此方案的核心是將需要分布式處理的任務通過消息日志的方式來異步執行。消息日志可以存儲到本地文本、數據庫或消息隊列,再通過業務規則自動或人工發起重試。人工重試更多的是應用于支付場景,通過對賬系統對事后問題的處理。
大致流程如下:
該方案與本地消息最大的不同是去掉了本地消息表,其次本地消息表依賴消息表重試寫入 mq 這一步由本方案中的輪詢 prepare 消息狀態來重試或者回滾該消息替代。其實現條件與余容錯方案基本一致。目前市面上實現該方案的只有阿里的 RocketMq。
最大努力通知是最簡單的一種柔性事務,適用于一些最終一致性時間敏感度低的業務,且被動方處理結果 不影響主動方的處理結果。
這個方案的大致意思就是:
七、分布式事務實戰
目前支付寶使用兩階段提交思想實現了分布式事務服務 (Distributed Transaction Service, DTS) ,它是一個分布式事務框架,用來保障在大規模分布式環境下事務的最終一致性。具體可參考支付寶官方文檔:
https://tech.antfin.com/docs/2/46887
TCC
TCC 需要事務接口提供 try, confirm, cancel 三個接口,提高了編程的復雜性。依賴于業務方來配合提供這樣的接口,推行難度大,所以一般不推薦使用這種方式。
可靠消息最終一致性
目前市面上支持該方案的 mq 只有阿里的 rocketmq, 該方案應用場景也比較多,比如用戶注冊成功后發送郵件、電商系統給用戶發送優惠券等需要保證最終一致性的場景
本地消息表
跨行轉賬可通過該方案實現。
用戶 A 向用戶 B 發起轉賬,首先系統會扣掉用戶 A 賬戶中的金額,將該轉賬消息寫入消息表中,如果事務執行失敗則轉賬失敗,如果轉賬成功,系統中會有定時輪詢消息表,往 mq 中寫入轉賬消息,失敗重試。mq 消息會被實時消費并往用戶 B 中賬戶增加轉賬金額,執行失敗會不斷重試。
小米海外商城用戶訂單數據狀態變更,會將變更狀態記錄消息表中,腳本將訂單狀態消息寫入 mq,最終消費 mq 給用戶發送郵件、短信、push 等。
最大努力通知
最大努力通知最常見的場景就是支付回調,支付服務收到第三方服務支付成功通知后,先更新自己庫中訂單支付狀態,然后同步通知訂單服務支付成功。如果此次同步通知失敗,會通過異步腳步不斷重試地調用訂單服務的接口。
小米海外商城目前除了支付回調外,最常用的場景是訂單數據同步。例如系統 A、B 進行數據同步,當系統 A 發生訂單數據變更,先將數據變更消息寫入小米 notify 系統(作用等同 mq),然后 notify 系統異步處理該消息來調用系統 B 提供的接口并進行重試到最大次數。
八、總結
本文介紹了分布式事務的一些基礎理論,并對常用的分布式事務方案進行了講解,在文章的后半部分主要給出了各種方案的常用場景。分布式事務本身就是一個技術難題,業務中具體使用哪種方案還是需要根據自身業務特點自行選擇,每種方案在實際執行過程中需要考慮的點都非常多,復雜度較大,所以在非必要的情況下,分布式事務能不用就盡量不用。
文章轉自
參考文章
總結
- 上一篇: 精选文章 什么是跨域?怎么解决跨域问题?
- 下一篇: 京东数据产品专家分享“如何转行数据产品经