現今互聯網界,分佈式系統和微服務架構盛行。業界著名的CAP理論也告訴咱們,在設計和實現一個分佈式系統時,須要將數據一致性、系統可用性和分區容忍性放在一塊兒考慮。算法
一、CAP理論數據庫
在分佈式系統中,一致性(Consistency)、可用性(Availability)和分區容忍性(Partition Tolerance)3 個要素最多隻能同時知足兩個,不可兼得。其中,分區容忍性又是不可或缺的。網絡
一致性:分佈式環境下多個節點的數據是否強一致。架構
可用性:分佈式服務能一直保證可用狀態。當用戶發出一個請求後,服務能在有限時間內返回結果。併發
分區容忍性:特指對網絡分區的容忍性。app
舉例:Cassandra、Dynamo 等,默認優先選擇AP,弱化C;HBase、MongoDB 等,默認優先選擇CP,弱化A。異步
二、BASE 理論分佈式
核心思想:ide
基本可用(Basically Available):指分佈式系統在出現故障時,容許損失部分的可用性來保證核心可用。微服務
軟狀態(Soft State):指容許分佈式系統存在中間狀態,該中間狀態不會影響到系統的總體可用性。
最終一致性(Eventual Consistency):指分佈式系統中的全部副本數據通過必定時間後,最終可以達到一致的狀態。
數據的一致性模型能夠分紅如下 3 類:
強一致性:數據更新成功後,任意時刻全部副本中的數據都是一致的,通常採用同步的方式實現。
弱一致性:數據更新成功後,系統不承諾當即能夠讀到最新寫入的值,也不承諾具體多久以後能夠讀到。
最終一致性:弱一致性的一種形式,數據更新成功後,系統不承諾當即能夠返回最新寫入的值,可是保證最終會返回上一次更新操做的值。
分佈式系統數據的強一致性、弱一致性和最終一致性能夠經過Quorum NRW算法分析。
分佈式事務的目的是保障分佈式存儲中數據一致性,而跨庫事務會遇到各類不可控制的問題,如個別節點宕機,像單機事務同樣的ACID是沒法奢望的。一、Two/Three Phase Commit2PC,中文叫兩階段提交。在分佈式系統中,每一個節點雖然能夠知曉本身的操做時成功或者失敗,卻沒法知道其餘節點的操做的成功或失敗。當一個事務跨越多個節點時,爲了保持事務的ACID特性,須要引入一個做爲協調者的組件來統一掌控全部節點(稱做參與者)的操做結果並最終指示這些節點是否要把操做結果進行真正的提交。兩階段提交的算法以下:第一階段:
第二階段:
兩段提交最大的問題就是第3)項,若是第一階段完成後,參與者在第二階沒有收到決策,那麼數據結點會進入「不知所措」的狀態,這個狀態會block住整個事務。也就是說,協調者Coordinator對於事務的完成很是重要,Coordinator的可用性是個關鍵。因些,咱們引入三段提交,三段提交在Wikipedia上的描述以下,他把二段提交的第一個段break成了兩段:詢問,而後再鎖資源。最後真正提交。三段提交的核心理念是:在詢問的時候並不鎖定資源,除非全部人都贊成了,纔開始鎖資源。但三階段提交也存在一些缺陷,要完全從協議層面避免數據不一致,能夠採用Paxos或者Raft 算法。目前兩階段提交、三階段提交存在以下的侷限性,並不適合在微服務架構體系下使用:
二、Try Confirm Cancel(TCC)
一個完整的TCC業務由一個主業務服務和若干個從業務服務組成,主業務服務發起並完成整個業務活動,TCC模式要求從服務提供三個接口:Try、Confirm、Cancel。
Try:完成全部業務檢查,預留必須業務資源。
Confirm:真正執行業務,不做任何業務檢查;只使用Try階段預留的業務資源;Confirm操做知足冪等性。
Cancel:釋放Try階段預留的業務資源;Cancel操做知足冪等性。
整個TCC業務分紅兩個階段完成:
第一階段:主業務服務分別調用全部從業務的try操做,並在活動管理器中登記全部從業務服務。當全部從業務服務的try操做都調用成功或者某個從業務服務的try操做失敗,進入第二階段。第二階段:活動管理器根據第一階段的執行結果來執行confirm或cancel操做。若是第一階段全部try操做都成功,則活動管理器調用全部從業務活動的confirm操做。不然調用全部從業務服務的cancel操做。與2PC比較:
缺點:
三、基於消息的分佈式事務
核心思想:
eBay 的架構師Dan Pritchett,曾在一篇解釋BASE 原理的論文《Base:An Acid Alternative》中提到一個eBay 分佈式系統一致性問題的解決方案。它的核心思想是將須要分佈式處理的任務經過消息或者日誌的方式來異步執行,消息或日誌能夠存到本地文件、數據庫或消息隊列,再經過業務規則進行失敗重試,它要求各服務的接口是冪等的。
基於消息的分佈式事務模式核心思想是經過消息系統來通知其餘事務參與方本身事務的執行狀態。消息系統的引入更有效的將事務參與方解耦,各個參與方能夠異步執行。
該種模式的難點在於解決本地事務執行和消息發送的一致性:二者要同時執行成功或者同時取消執行。
實現上主要有兩種方式:
基於事務消息的方案
基於本地消息的方案
1)基於事務消息的分佈式事務普通消息是沒法解決本地事務執行和消息發送的一致性問題的。由於消息發送是一個網絡通訊的過程,發送消息的過程就有可能出現發送失敗、或者超時的狀況。超時有可能發送成功了,有可能發送失敗了,消息的發送方是沒法肯定的,因此此時消息發送方不管是提交事務仍是回滾事務,都有可能不一致性出現。解決這個問題,須要引入事務消息,事務消息和普通消息的區別在於事務消息發送成功後,處於 prepared 狀態,不能被訂閱者消費,等到事務消息的狀態更改成可消費狀態後,下游訂閱者才能夠監聽到次消息。本地事務和事務消息的發送的處理流程以下:
2)基於本地消息的分佈式事務
基於事務消息的模式對 MQ 系統要求較高,並非全部 MQ 系統都支持事務消息的,RocketMQ 是目前爲數很少的支持事務消息的 MQ 系統。若是所依賴的 MQ 系統不支持事務消息,那麼能夠採用本地消息的分佈式模式。該種模式的核心思想是:上游服務:
下游服務:
基於消息的分佈式事務能夠將分佈式系統之間更有效的解耦,各個事務參與方之間的調用再也不是同步調用。
對MQ系統的要求較高,對業務實現也有必定的侵入性,要麼提供事務消息狀態查詢接口,要麼須要維護本地消息表。而且原則上只接受下游分支事務的成功,不接受事務的回滾,若是失敗就要一直重試,適用於對最終一致性敏感度較低的業務場景,例如跨企業的系統間的調用,適用的場景有限。
總結
閱讀了很多這方面的文章,在此基礎上,總結一下分佈式事務一致性的解決方案。分佈式系統的事務一致性自己就是一個技術難題,目前沒有一種很簡單很完美的方案可以應對全部場景。分佈式系統的一個難點就是由於「網絡通訊的不可靠」,只能經過「確認機制」、「重試機制」、「補償機制」等各方面來解決問題。在綜合考慮可用性、性能、實現複雜度等各方面的狀況上,比較好的選擇是「異步消息確保最終一致性」,只是具體實現方式上有一些差別。