微服務架構下處理分布式事務,你必須知道的事兒
根據(jù)微服務架構的鼻祖 Martin Fowler 的忠告,微服務架構中應當盡量避免分布式事務。然而,在某些領域,分布式事務如同宿***的對手無法避免。
在工程領域,分布式事務的討論主要聚焦于強一致性和最終一致性的解決方案。
典型方案包括:
- 兩階段提交(2PC, Two-phase Commit)方案。
- eBay 事件隊列方案。
- TCC 補償模式。
- 緩存數(shù)據(jù)最終一致性。
一致性理論
分布式事務的目的是保障分庫數(shù)據(jù)一致性,而跨庫事務會遇到各種不可控制的問題,如個別節(jié)點***性宕機,像單機事務一樣的 ACID 是無法奢望的。
另外,業(yè)界著名的 CAP 理論也告訴我們,對分布式系統(tǒng),需要將數(shù)據(jù)一致性和系統(tǒng)可用性、分區(qū)容忍性放在天平上一起考慮。
兩階段提交協(xié)議(簡稱2PC)是實現(xiàn)分布式事務較為經(jīng)典的方案,但 2PC 的可擴展性很差,在分布式架構下應用代價較大,eBay 架構師 Dan Pritchett 提出了 BASE 理論,用于解決大規(guī)模分布式系統(tǒng)下的數(shù)據(jù)一致性問題。
BASE 理論告訴我們:可以通過放棄系統(tǒng)在每個時刻的強一致性來換取系統(tǒng)的可擴展性。
01.CAP 理論
在分布式系統(tǒng)中,一致性(Consistency)、可用性(Availability)和分區(qū)容忍性(Partition Tolerance)3 個要素最多只能同時滿足兩個,不可兼得。其中,分區(qū)容忍性又是不可或缺的。
- 一致性:分布式環(huán)境下,多個節(jié)點的數(shù)據(jù)是否強一致。
- 可用性:分布式服務能一直保證可用狀態(tài)。當用戶發(fā)出一個請求后,服務能在有限時間內返回結果。
- 分區(qū)容忍性:特指對網(wǎng)絡分區(qū)的容忍性。
舉例:Cassandra、Dynamo 等,默認優(yōu)先選擇 AP,弱化 C;HBase、MongoDB 等,默認優(yōu)先選擇 CP,弱化 A。
02.BASE 理論
核心思想:
- 基本可用(Basically Available):指分布式系統(tǒng)在出現(xiàn)故障時,允許損失部分的可用性來保證核心可用。
- 軟狀態(tài)(Soft State):指允許分布式系統(tǒng)存在中間狀態(tài),該中間狀態(tài)不會影響到系統(tǒng)的整體可用性。
- 最終一致性(Eventual Consistency):指分布式系統(tǒng)中的所有副本數(shù)據(jù)經(jīng)過一定時間后,最終能夠達到一致的狀態(tài)。
一致性模型
數(shù)據(jù)的一致性模型可以分成以下三類:
- 強一致性:數(shù)據(jù)更新成功后,任意時刻所有副本中的數(shù)據(jù)都是一致的,一般采用同步的方式實現(xiàn)。
- 弱一致性:數(shù)據(jù)更新成功后,系統(tǒng)不承諾立即可以讀到***寫入的值,也不承諾具體多久之后可以讀到。
- 最終一致性:弱一致性的一種形式,數(shù)據(jù)更新成功后,系統(tǒng)不承諾立即可以返回***寫入的值,但是保證最終會返回上一次更新操作的值。
分布式系統(tǒng)數(shù)據(jù)的強一致性、弱一致性和最終一致性可以通過 Quorum NRW 算法分析。
分布式事務解決方案
01.2PC 方案——強一致性
2PC 的核心原理是通過提交分階段和記日志的方式,記錄下事務提交所處的階段狀態(tài),在組件宕機重啟后,可通過日志恢復事務提交的階段狀態(tài),并在這個狀態(tài)節(jié)點重試。
如 Coordinator 重啟后,通過日志可以確定提交處于 Prepare 還是 Prepare All 狀態(tài)。若是前者,說明有節(jié)點可能沒有 Prepare 成功,或所有節(jié)點 Prepare 成功但還沒有下發(fā) Commit,狀態(tài)恢復后給所有節(jié)點下發(fā) RollBack。
若是 Prepare All 狀態(tài),需要給所有節(jié)點下發(fā) Commit,數(shù)據(jù)庫節(jié)點需要保證 Commit 冪等。
2PC 方案的三個問題:
- 同步阻塞。
- 數(shù)據(jù)不一致。
- 單點問題。
升級的 3PC 方案旨在解決這些問題,主要有兩個改進:
- 增加超時機制。
- 兩階段之間插入準備階段。
但三階段提交也存在一些缺陷,要徹底從協(xié)議層面避免數(shù)據(jù)不一致,可以采用 Paxos 或者 Raft 算法。
02.eBay 事件隊列方案——最終一致性
eBay 的架構師 Dan Pritchett,曾在一篇解釋 BASE 原理的論文《Base:An Acid Alternative》中提到一個 eBay 分布式系統(tǒng)一致性問題的解決方案。
它的核心思想是將需要分布式處理的任務通過消息或者日志的方式來異步執(zhí)行,消息或日志可以存到本地文件、數(shù)據(jù)庫或消息隊列,再通過業(yè)務規(guī)則進行失敗重試,它要求各服務的接口是冪等的。
描述的場景為,有用戶表 user 和交易表 transaction,用戶表存儲用戶信息、總銷售額和總購買額。交易表存儲每一筆交易的流水號、買家信息、賣家信息和交易金額。如果產(chǎn)生了一筆交易,需要在交易表增加記錄,同時還要修改用戶表的金額。
論文中提出的解決方法是將更新交易表記錄和用戶表更新消息放在一個本地事務來完成,為了避免重復消費用戶表更新消息帶來的問題,增加一個操作記錄表 updates_applied 來記錄已經(jīng)完成的交易相關的信息。
這個方案的核心在于第二階段的重試和冪等執(zhí)行。失敗后重試,這是一種補償機制,它是能保證系統(tǒng)最終一致的關鍵流程。
03.TCC (Try-Confirm-Cancel)補償模式——最終一致性
某業(yè)務模型如圖,由服務 A、服務 B、服務 C、服務 D 共同組成的一個微服務架構系統(tǒng)。服務 A 需要依次調用服務 B、服務 C 和服務 D 共同完成一個操作。
當服務 A 調用服務 D 失敗時,若要保證整個系統(tǒng)數(shù)據(jù)的一致性,就要對服務 B 和服務 C 的 invoke 操作進行回滾,執(zhí)行反向的 revert 操作。回滾成功后,整個微服務系統(tǒng)是數(shù)據(jù)一致的。
實現(xiàn)的三個關鍵要素:
- 服務調用鏈必須被記錄下來。
- 每個服務提供者都需要提供一組業(yè)務邏輯相反的操作,互為補償,同時回滾操作要保證冪等。
- 必須按失敗原因執(zhí)行不同的回滾策略。
實現(xiàn)的兩個難點:
- 補償模式的特點是實現(xiàn)簡單,但是想形成一定程度的通用方案比較困難,特別是服務鏈的記錄,因為大部分時候,業(yè)務參數(shù)或者業(yè)務邏輯千差萬別。
- 很多業(yè)務特征使得該服務無法提供一個安全的回滾操作。
04.緩存數(shù)據(jù)最終一致性
在我們的業(yè)務系統(tǒng)中,緩存(Redis 或者 Memcached)通常被用在數(shù)據(jù)庫前面,作為數(shù)據(jù)讀取的緩沖,使得 I/O 操作不至于直接落在數(shù)據(jù)庫上。
以商品詳情頁為例,假如賣家修改了商品信息,并寫回到數(shù)據(jù)庫,但是這時候用戶從商品詳情頁看到的信息還是從緩存中拿到的過時數(shù)據(jù),這就出現(xiàn)了緩存系統(tǒng)和數(shù)據(jù)庫系統(tǒng)中的數(shù)據(jù)不一致的現(xiàn)象。
要解決該場景下緩存和數(shù)據(jù)庫數(shù)據(jù)不一致的問題,我們有以下兩種解決方案:
- 為緩存數(shù)據(jù)設置過期時間。當緩存中數(shù)據(jù)過期后,業(yè)務系統(tǒng)會從數(shù)據(jù)庫中獲取數(shù)據(jù),并將新值放入緩存。這個過期時間就是系統(tǒng)可以達到最終一致的容忍時間。
- 更新數(shù)據(jù)庫數(shù)據(jù)后,同時清除緩存數(shù)據(jù)。數(shù)據(jù)庫數(shù)據(jù)更新后,同步刪除緩存中數(shù)據(jù),使得下次對商品詳情的獲取直接從數(shù)據(jù)庫中獲取,并同步到緩存。
選擇建議
在面臨數(shù)據(jù)一致性問題的時候,首先要從業(yè)務需求的角度出發(fā),確定我們對于三種一致性模型的接受程度,再通過具體場景來決定解決方案。
從應用角度看,分布式事務的現(xiàn)實場景常常無法規(guī)避,在有能力給出其他解決方案前,2PC 也是一個不錯的選擇。
對購物轉賬等電商和金融業(yè)務,中間件層的 2PC ***問題在于業(yè)務不可見,一旦出現(xiàn)不可抗力或意想不到的一致性破壞。
如數(shù)據(jù)節(jié)點***性宕機,業(yè)務難以根據(jù) 2PC 的日志進行補償。金融場景下,數(shù)據(jù)一致性是命根,業(yè)務需要對數(shù)據(jù)有***的掌控力。
建議使用 TCC 這類分布式事務模型,或基于消息隊列的柔性事務框架,這兩種方案都在業(yè)務層實現(xiàn),業(yè)務開發(fā)者具有足夠掌控力,可以結合 SOA 框架來架構,包括 Dubbo、Spring Cloud 等。