關(guān)于分布式事務(wù),工程領(lǐng)域主要討論的是強(qiáng)一致性和最終一致性的解決方案。典型方案包括:
兩階段提交(2PC, Two-phase Commit)方案
eBay 事件隊(duì)列方案
TCC 補(bǔ)償模式
緩存數(shù)據(jù)最終一致性
一、一致性理論
分布式事務(wù)的目的是保障分庫數(shù)據(jù)一致性,而跨庫事務(wù)會(huì)遇到各種不可控制的問題,如個(gè)別節(jié)點(diǎn)永久性宕機(jī),像單機(jī)事務(wù)一樣的ACID是無法奢望的。另外,業(yè)界著名的CAP理論也告訴我們,對分布式系統(tǒng),需要將數(shù)據(jù)一致性和系統(tǒng)可用性、分區(qū)容忍性放在天平上一起考慮。
兩階段提交協(xié)議(簡稱2PC)是實(shí)現(xiàn)分布式事務(wù)較為經(jīng)典的方案,但2PC 的可擴(kuò)展性很差,在分布式架構(gòu)下應(yīng)用代價(jià)較大,eBay 架構(gòu)師Dan Pritchett 提出了BASE 理論,用于解決大規(guī)模分布式系統(tǒng)下的數(shù)據(jù)一致性問題。BASE 理論告訴我們:可以通過放棄系統(tǒng)在每個(gè)時(shí)刻的強(qiáng)一致性來換取系統(tǒng)的可擴(kuò)展性。
1、CAP理論
在分布式系統(tǒng)中:
一致性(Consistency)
可用性(Availability)
分區(qū)容忍性(Partition Tolerance)
3個(gè)要素最多只能同時(shí)滿足兩個(gè),不可兼得。其中,分區(qū)容忍性又是不可或缺的。

一致性:分布式環(huán)境下多個(gè)節(jié)點(diǎn)的數(shù)據(jù)是否強(qiáng)一致。
可用性:分布式服務(wù)能一直保證可用狀態(tài)。當(dāng)用戶發(fā)出一個(gè)請求后,服務(wù)能在有限時(shí)間內(nèi)返回結(jié)果。
分區(qū)容忍性:特指對網(wǎng)絡(luò)分區(qū)的容忍性。
舉例:Cassandra、Dynamo 等,默認(rèn)優(yōu)先選擇AP,弱化C;HBase、MongoDB 等,默認(rèn)優(yōu)先選擇CP,弱化A。
2、BASE 理論
核心思想:
基本可用(BasicallyAvailable):指分布式系統(tǒng)在出現(xiàn)故障時(shí),允許損失部分的可用性來保證核心可用。
軟狀態(tài)(SoftState):指允許分布式系統(tǒng)存在中間狀態(tài),該中間狀態(tài)不會(huì)影響到系統(tǒng)的整體可用性。
最終一致性(EventualConsistency):指分布式系統(tǒng)中的所有副本數(shù)據(jù)經(jīng)過一定時(shí)間后,最終能夠達(dá)到一致的狀態(tài)。
二、一致性模型
數(shù)據(jù)的一致性模型可以分成以下 3 類:
強(qiáng)一致性:數(shù)據(jù)更新成功后,任意時(shí)刻所有副本中的數(shù)據(jù)都是一致的,一般采用同步的方式實(shí)現(xiàn)。
弱一致性:數(shù)據(jù)更新成功后,系統(tǒng)不承諾立即可以讀到最新寫入的值,也不承諾具體多久之后可以讀到。
最終一致性:弱一致性的一種形式,數(shù)據(jù)更新成功后,系統(tǒng)不承諾立即可以返回最新寫入的值,但是保證最終會(huì)返回上一次更新操作的值。
分布式系統(tǒng)數(shù)據(jù)的強(qiáng)一致性、弱一致性和最終一致性可以通過Quorum NRW算法分析。
三、分布式事務(wù)解決方案
1、2PC方案——強(qiáng)一致性
2PC的核心原理是通過提交分階段和記日志的方式,記錄下事務(wù)提交所處的階段狀態(tài),在組件宕機(jī)重啟后,可通過日志恢復(fù)事務(wù)提交的階段狀態(tài),并在這個(gè)狀態(tài)節(jié)點(diǎn)重試,如Coordinator重啟后,通過日志可以確定提交處于Prepare還是PrepareAll狀態(tài),若是前者,說明有節(jié)點(diǎn)可能沒有Prepare成功,或所有節(jié)點(diǎn)Prepare成功但還沒有下發(fā)Commit,狀態(tài)恢復(fù)后給所有節(jié)點(diǎn)下發(fā)RollBack;若是PrepareAll狀態(tài),需要給所有節(jié)點(diǎn)下發(fā)Commit,數(shù)據(jù)庫節(jié)點(diǎn)需要保證Commit冪等。

2PC方案的問題:
同步阻塞。
數(shù)據(jù)不一致。
單點(diǎn)問題。
升級的3PC方案旨在解決這些問題,主要有兩個(gè)改進(jìn):
增加超時(shí)機(jī)制。
兩階段之間插入準(zhǔn)備階段。
但三階段提交也存在一些缺陷,要徹底從協(xié)議層面避免數(shù)據(jù)不一致,可以采用Paxos或者Raft 算法。
Paxos:en.wikipedia.org/wiki/Paxos_…
Raft:raft.github.io/
2、eBay 事件隊(duì)列方案——最終一致性
eBay 的架構(gòu)師Dan Pritchett,曾在一篇解釋BASE 原理的論文《Base:An Acid Alternative》中提到一個(gè)eBay 分布式系統(tǒng)一致性問題的解決方案。它的核心思想是將需要分布式處理的任務(wù)通過消息或者日志的方式來異步執(zhí)行,消息或日志可以存到本地文件、數(shù)據(jù)庫或消息隊(duì)列,再通過業(yè)務(wù)規(guī)則進(jìn)行失敗重試,它要求各服務(wù)的接口是冪等的。
Base:An Acid Alternative:link.zhihu.com/?target=htt…
描述的場景為,有用戶表user 和交易表transaction,用戶表存儲(chǔ)用戶信息、總銷售額和總購買額,交易表存儲(chǔ)每一筆交易的流水號、買家信息、賣家信息和交易金額。如果產(chǎn)生了一筆交易,需要在交易表增加記錄,同時(shí)還要修改用戶表的金額

論文中提出的解決方法是將更新交易表記錄和用戶表更新消息放在一個(gè)本地事務(wù)來完成,為了避免重復(fù)消費(fèi)用戶表更新消息帶來的問題,增加一個(gè)操作記錄表updates_applied來記錄已經(jīng)完成的交易相關(guān)的信息。

這個(gè)方案的核心在于第二階段的重試和冪等執(zhí)行。失敗后重試,這是一種補(bǔ)償機(jī)制,它是能保證系統(tǒng)最終一致的關(guān)鍵流程。
3、TCC (Try-Confirm-Cancel)補(bǔ)償模式——最終一致性
某業(yè)務(wù)模型如圖,由服務(wù) A、服務(wù)B、服務(wù)C、服務(wù)D 共同組成的一個(gè)微服務(wù)架構(gòu)系統(tǒng)。服務(wù)A 需要依次調(diào)用服務(wù)B、服務(wù)C 和服務(wù)D 共同完成一個(gè)操作。當(dāng)服務(wù)A 調(diào)用服務(wù)D 失敗時(shí),若要保證整個(gè)系統(tǒng)數(shù)據(jù)的一致性,就要對服務(wù)B 和服務(wù)C 的invoke 操作進(jìn)行回滾,執(zhí)行反向的revert 操作?;貪L成功后,整個(gè)微服務(wù)系統(tǒng)是數(shù)據(jù)一致的。

實(shí)現(xiàn)關(guān)鍵要素:
服務(wù)調(diào)用鏈必須被記錄下來。
每個(gè)服務(wù)提供者都需要提供一組業(yè)務(wù)邏輯相反的操作,互為補(bǔ)償,同時(shí)回滾操作要保證冪等。
必須按失敗原因執(zhí)行不同的回滾策略。
4、緩存數(shù)據(jù)最終一致性
在我們的業(yè)務(wù)系統(tǒng)中,緩存(Redis 或者M(jìn)emcached)通常被用在數(shù)據(jù)庫前面,作為數(shù)據(jù)讀取的緩沖,使得I/O 操作不至于直接落在數(shù)據(jù)庫上。以商品詳情頁為例,假如賣家修改了商品信息,并寫回到數(shù)據(jù)庫,但是這時(shí)候用戶從商品詳情頁看到的信息還是從緩存中拿到的過時(shí)數(shù)據(jù),這就出現(xiàn)了緩存系統(tǒng)和數(shù)據(jù)庫系統(tǒng)中的數(shù)據(jù)不一致的現(xiàn)象。
要解決該場景下緩存和數(shù)據(jù)庫數(shù)據(jù)不一致的問題我們有以下兩種解決方案:
為緩存數(shù)據(jù)設(shè)置過期時(shí)間。當(dāng)緩存中數(shù)據(jù)過期后,業(yè)務(wù)系統(tǒng)會(huì)從數(shù)據(jù)庫中獲取數(shù)據(jù),并將新值放入緩存。這個(gè)過期時(shí)間就是系統(tǒng)可以達(dá)到最終一致的容忍時(shí)間。更新數(shù)據(jù)庫數(shù)據(jù)后同時(shí)清除緩存數(shù)據(jù)。數(shù)據(jù)庫數(shù)據(jù)更新后,同步刪除緩存中數(shù)據(jù),使得下次對商品詳情的獲取直接從數(shù)據(jù)庫中獲取,并同步到緩存。
四、選擇建議
在面臨數(shù)據(jù)一致性問題的時(shí)候,首先要從業(yè)務(wù)需求的角度出發(fā),確定我們對于3 種一致性模型的接受程度,再通過具體場景來決定解決方案。
從應(yīng)用角度看,分布式事務(wù)的現(xiàn)實(shí)場景常常無法規(guī)避,在有能力給出其他解決方案前,2PC也是一個(gè)不錯(cuò)的選擇。
對購物轉(zhuǎn)賬等電商和金融業(yè)務(wù),中間件層的2PC最大問題在于業(yè)務(wù)不可見,一旦出現(xiàn)不可抗力或意想不到的一致性破壞,如數(shù)據(jù)節(jié)點(diǎn)永久性宕機(jī),業(yè)務(wù)難以根據(jù)2PC的日志進(jìn)行補(bǔ)償。金融場景下,數(shù)據(jù)一致性是命根,業(yè)務(wù)需要對數(shù)據(jù)有百分之百的掌控力,建議使用TCC這類分布式事務(wù)模型,或基于消息隊(duì)列的柔性事務(wù)框架,這兩種方案都在業(yè)務(wù)層實(shí)現(xiàn),業(yè)務(wù)開發(fā)者具有足夠掌控力,可以結(jié)合SOA框架來架構(gòu),包括Dubbo、Spring Cloud等(題主的標(biāo)簽寫了Dubbo)