關係型數據庫具備解決復瑣事務場景的能力,關係型數據庫的事務知足 ACID 的特性。數據庫
Atomicity:原子性(要麼都作,要麼都不作)後端
Consistency:一致性(數據庫只有一個狀態,不存在未肯定狀態)網絡
Isolation:隔離性(事務之間互不干擾)併發
Durability: 永久性(事務一旦提交,數據庫記錄永久不變)分佈式
具備 ACID 特性的數據庫支持數據的強一致性,保證了數據自己不會出現不一致。高併發
CAP 是指在一個分佈式系統下, 包含三個要素:Consistency(一致性)、Availability(可用性)、Partition tolerance(分區容錯性),而且三者不可得兼。性能
C:Consistency,一致性,全部數據變更都是同步的。spa
A:Availability,可用性,即在能夠接受的時間範圍內正確地響應用戶請求。3d
P:Partition tolerance,分區容錯性,即某節點或網絡分區故障時,系統仍可以提供知足一致性和可用性的服務。日誌
關係型數據庫單節點保證了數據強一致性(C)和可用性(A),可是卻沒法保證分區容錯性(P)。
然而在分佈式系統下,爲了保證模塊的分區容錯性(P),只能在數據強一致性(C)和可用性(A)之間作平衡。具體表現爲在必定時間內,可能模塊之間數據是不一致的,可是經過自動或手動補償後可以達到最終的一致。
BASE 理論主要是解決 CAP 理論中分佈式系統的可用性和一致性不可兼得的問題。BASE 理論包含如下三個要素:
BA:Basically Available,基本可用。
S:Soft State,軟狀態,狀態能夠有一段時間不一樣步。
E:Eventually Consistent,最終一致,最終數據是一致的就能夠了,而不是時時保持強一致。
BASE 模型與 ACID 不一樣,知足 CAP 理論,經過犧牲強一致性來保證系統可用性。因爲犧牲了強一致性,系統在處理請求的過程當中,數據能夠存在短時的不一致。
系統在處理業務時,記錄每一步的臨時狀態。當出現異常時,根據狀態判斷是否繼續處理請求或者退回原始狀態,從而達到數據的最終一致。
X/Open DTP(Distributed Transaction Process)是一個分佈式事務模型,此模型主要使用二階段提交(2PC,Two-Phase-Commit)來保證分佈式事務的完整性。在這個模型裏面,有三個角色:
AP:Application,應用程序,業務層。
RM:Resource Manager,資源管理器,關係型數據庫或支持 XA 接口(XA 規範是 X/Open 組織定義的分佈式事務規範)的組件。
TM: Transaction Manager ,事務管理器,負責各個 RM 的提交和回滾。
當應用程序(AP)調用了事務管理器(TM)的提交方法時,事務的提交分爲兩個階段實行。
TM 通知全部參與事務的各個 RM,給每一個 RM 發送 prepare 消息。
RM 接收到消息後進入準備階段後,要麼直接返回失敗,要麼建立並執行本地事務,寫本地事務日誌(redo 和 undo 日誌),可是不提交(此處只保留最後一步耗時最少的提交操做給第二階段執行)。
TM 收到 RM 準備階段的失敗消息或者獲取 RM 返回消息超時,則直接給 RM 發送回滾(rollback)消息,不然發送提交(commit)消息。
RM 根據 TM 的指令執行提交或者回滾,執行完成後釋放全部事務處理過程當中使用的鎖(最後階段釋放鎖)。
考慮數據庫事務的執行其實是先將執行操做寫入binlog,等到最後經過一個commit指令將binlog的內容一次更新到表中,或者寫到一半經過一個rollback指令將binlog中的內容回滾。能夠想到使用2個階段來執行這個過程,第一階段,寫入binlog;第二階段執行commit或者rollback。這就是著名的兩階段提交協議(2PC)。若是仔細考慮,會發現兩階段協議並無解決問題,只不過下降了出錯的機率而已,由於第二階段一樣存在一個提交成功一個被回滾,已提交的沒法被回滾的狀況。注意最終狀態是多臺機器的狀態&&求與的結果。
優勢
2PC 提供了一套完整的分佈式事務的解決方案,遵循事務嚴格的 ACID 特性。
缺點
TM 經過 XA 接口與各個 RM 之間進行數據交互,從第一階段的準備階段,業務所涉及的數據就被鎖定,而且鎖定跨越整個提交流程。在高併發和涉及業務模塊較多的狀況下對數據庫的性能影響較大。
二階段是反可伸縮模式的,業務規模越大,涉及模塊越多,侷限性越大,系統可伸縮性越差。
在技術棧比較雜的分佈式應用中,存儲組件有不少不支持 XA 協議。
二階段的諸多弊端,致使分佈式系統下沒法直接使用此方案來解決數據一致性問題,但它提供瞭解決分佈式系統下數據一致性問題的思路。
可靠消息最終一致性方案本質上是利用 MQ 組件實現的二階段提交。此方案涉及 3 個模塊:
上游應用,執行業務併發送 MQ 消息。
可靠消息服務和 MQ 消息組件,協調上下游消息的傳遞,並確保上下游數據的一致性。
下游應用,監聽 MQ 的消息並執行自身業務。
上游應用將本地業務執行和消息發送綁定在同一個本地事務中,保證本地操做成功併發送 MQ 消息,不然兩步操做都失敗並回滾。
上游應用發送待確認消息到可靠消息系統
可靠消息系統保存待確認消息並返回
上游應用執行本地業務
上游應用通知可靠消息系統確認業務已執行併發送消息。
可靠消息系統修改消息狀態爲發送狀態並將消息投遞到 MQ 中間件。
以上每一步均可能出現失敗狀況,分析一下這 5 步出現異常後上遊業務和消息發送是否一致:
上游應用執行完成,下游應用還沒有執行或執行失敗時,此事務即處於 BASE 理論的 Soft State 狀態。
下游應用監聽 MQ 消息並執行業務,而且將消息的消費結果通知可靠消息服務。
可靠消息的狀態須要和下游應用的業務執行保持一致,可靠消息狀態不是已完成時,確保下游應用未執行,可靠消息狀態是已完成時,確保下游應用已執行。
下游應用監聽 MQ 消息組件並獲取消息
下游應用根據 MQ 消息體信息處理本地業務
下游應用向 MQ 組件自動發送 ACK 確認消息被消費
下游應用通知可靠消息系統消息被成功消費,可靠消息將該消息狀態更改成已完成。
以上每一步均可能出現失敗狀況,分析一下這 4 步出現異常後下遊業務和消息狀態是否一致:
經過分析以上兩個階段可能失敗的狀況,爲了確保上下游數據的最終一致性,在可靠消息系統中,須要開發消息狀態確認和消息重發兩個功能以實現 BASE 理論的 Eventually Consistent 特性。
消息狀態確認:
可靠消息服務定時監聽消息的狀態,若是存在狀態爲待確認而且超時的消息,則表示上游應用和可靠消息交互中的步驟 4 或者 5 出現異常。
可靠消息查詢超時的待確認狀態的消息
向上遊應用查詢業務執行的狀況
業務未執行,則刪除該消息,保證業務和可靠消息服務的一致性。業務已執行,則修改消息狀態爲已發送,併發送消息到 MQ 組件。
消息重發:
消息已發送則表示上游應用已經執行,接下來則確保下游應用也能正常執行。
可靠消息服務發現可靠消息服務中存在消息狀態爲已發送而且超時的消息,則表示可靠消息服務和下游應用中存在異常的步驟,不管哪一個步驟出現異常,可靠消息服務都將此消息從新投遞到 MQ 組件中供下游應用監聽。
下游應用監聽到此消息後,在保證冪等性的狀況下從新執行業務並通知可靠消息服務此消息已經成功消費,最終確保上游應用、下游應用的數據最終一致性。
可靠消息服務定時查詢狀態爲已發送並超時的消息
可靠消息將消息從新投遞到 MQ 組件中
下游應用監聽消息,在知足冪等性的條件下,從新執行業務。
下游應用通知可靠消息服務該消息已經成功消費。
經過消息狀態確認和消息重發兩個功能,能夠確保上游應用、可靠消息服務和下游應用數據的最終一致性。
在實際接入過程當中,須要引入人工干預功能。好比引入重發次數限制,超太重發次數限制的將消息修改成死亡消息,等待人工干預。
業務補償類型,其基本思想是對每個業務操做作一個逆操做,一旦成功了,就作正向業務,一旦失敗了就作業務的逆操做。一般在業務邏輯簡單而且正逆操做清晰的時候用比較好。在技術棧統一的狀況下,可選擇 TCC 來解決數據一致的方法。
TCC 方案是二階段提交的另外一種實現方式,它涉及 3 個模塊,主業務、從業務和活動管理器(協做者)。
第一階段:主業務服務分別調用全部從業務服務的 try 操做,並在活動管理器中記錄全部從業務服務。當全部從業務服務 try 成功或者某個從業務服務 try 失敗時,進入第二階段。
第二階段:活動管理器根據第一階段從業務服務的 try 結果來執行 confirm 或 cancel 操做。若是第一階段全部從業務服務都 try 成功,則協做者調用全部從業務服務的 confirm 操做,不然,調用全部從業務服務的 cancel 操做。
在第二階段中,confirm 和 cancel 一樣存在失敗狀況,因此須要對這兩種狀況作異常處理以保證數據一致性。
Confirm 失敗:則回滾全部 confirm 操做並執行 cancel 操做。
Cancel 失敗:從業務服務須要提供自動 cancel 機制,以保證 cancel 成功。
基於 HTTP 協議的 TCC 實現:
主業務服務調用從業務服務的 try 操做,並獲取 confirm/cancel 接口和超時時間。
若是從業務都 try 成功,主業務服務執行本地業務,並將獲取的 confirm/cancel 接口發送給活動管理器,活動管理器會順序調用從業務 1 和從業務 2 的 confirm 接口並記錄請求狀態,若是請求成功,則通知主業務服務提交本地事務。若是 confirm 部分失敗,則活動管理器會順序調用從業務 1 和從業務 2 的 cancel 接口來取消 try 的操做。
若是從業務部分或所有 try 失敗,則主業務直接回滾並結束,而 try 成功的從業務服務則經過定時任務來處理處於 try 完成但超時的數據,將這些數據作回滾處理保證主業務服務和從業務服務的數據一致。
一般在覈心業務上有不少附加業務,好比當用戶支付完成後,須要經過短信通知用戶支付成功。這一類業務的成功或者失敗不會影響核心業務,甚至不少大型互聯網平臺在並高併發的狀況下會主動關閉這一類業務以保證核心業務的順利執行。那麼怎麼處理這類狀況呢,來看看最大努力通知方案。
最大努力通知方案涉及三個模塊:
上游應用,發消息到 MQ 隊列。
下游應用(例如短信服務、郵件服務),接受請求,並返回通知結果。
最大努力通知服務 監聽消息隊列,將消息存儲到數據庫中,並按照通知規則調用下游應用的發送通知接口。
最大努力通知服務表示在不影響主業務的狀況下,儘量地確保數據的一致性。它須要開發人員根據業務來指定通知規則,在知足通知規則的前提下,儘量的確保數據的一致,以盡到最大努力的目的。
上游應用發送 MQ 消息到 MQ 組件內,消息內包含通知規則和通知地址
最大努力通知服務監聽到 MQ 內的消息,解析通知規則並放入延時隊列等待觸發通知
最大努力通知服務調用下游的通知地址,若是調用成功,則該消息標記爲通知成功,若是失敗則在知足通知規則(例如 5 分鐘發一次,共發送 10 次)的狀況下從新放入延時隊列等待下次觸發。
典型的場景是向銀行發送了轉帳請求未獲得明確的成功失敗返回碼,此時先作業務結果的查詢,根據結果作相應處理,好比查詢結果成功,則置狀態爲成功,查詢結果失敗,則作相應的業務補償,查詢結果爲未知,則繼續查詢。