原文連接: blog.wangriyu.wang/2018/06-Dis…html
CAP 定理指出對於一個分佈式系統來講,不可能同時知足如下三點:mysql
一個分佈式系統裏面,節點組成的網絡原本應該是連通的。然而可能由於一些故障或者延時,使得有些節點之間不連通了,整個網絡就分紅了幾塊區域。數據就散佈在了這些不連通的區域中,這就叫分區。當你一個數據項只在一個節點中保存,那麼分區出現後,和這個節點不連通的部分就訪問不到這個數據了。這時分區就是沒法容忍的。提升分區容忍性的辦法就是將一個數據項複製到多個節點上,那麼出現分區以後,這一數據項就可能分佈到各個區裏,容忍性就提升了。然而,要把數據複製到多個節點,就會帶來一致性的問題,就是多個節點上面的數據多是不一致的。要保證一致,每次寫操做就都要等待所有節點寫成功,而這等待又會帶來可用性的問題。總的來講就是,數據存在的節點越多,分區容忍性越高,但要複製更新的數據就越多,一致性就越難保證。爲了保證一致性,更新全部節點數據所須要的時間就越長,可用性就會下降 -- 來自知乎鄔江的回答算法
CAP 理論實際想表達的是任何分佈式系統不能同時知足強一致性、高可用性和較好的分區容錯性sql
RDBMS: Relational Database Management System,關係型數據庫管理系統數據庫
由 CAP 定理可知數據庫的設計須要權衡取捨,因此能夠把數據庫大體分爲三類:服務器
分佈式和集羣的區別:網絡
分佈式: 不一樣的多臺服務器上面部署不一樣的服務模塊,他們之間經過 Rpc/HTTP 等方式進行通訊和調用,對外提供服務和組內協做架構
集羣: 不一樣的多臺服務器上面部署相同的服務模塊,經過分佈式調度軟件進行統一的調度,對外提供服務和訪問併發
ACID 指的是傳統數據庫中事務操做所具有的四個特性:異步
BASE 理論是對 CAP 理論的延伸,核心思想是雖然沒法作到強一致性 (Strong Consistency),但能夠採用適合的方式達到最終一致性 (Eventual Consitency)
BASE 包含三部分:
ACID 隸屬於 CA,是傳統數據庫經常使用的設計理念,追求強一致性模型
BASE 隸屬於 AP,支持的是大型分佈式系統,提出經過犧牲強一致性得到高可用性
但在實際的分佈式場景中,不一樣業務單元和組件對數據一致性的要求是不一樣的,所以在具體的分佈式系統架構設計過程當中,ACID 特性與 BASE 理論每每會結合在一塊兒使用。好比總體知足 BASE,局部知足 ACID。
上述最終一致性的不一樣方式能夠進行組合,例如單調讀一致性和讀己之所寫一致性就能夠組合實現。而且從實踐的角度來看,這二者的組合,讀取本身更新的數據,和一旦讀取到最新的版本不會再讀取舊版本,對於此架構上的程序開發來講,會少不少額外的煩惱。
從服務端角度,如何儘快將更新後的數據分佈到整個系統,下降達到最終一致性的時間窗口,是提升系統的可用度和用戶體驗很是重要的方面。
爲了解決分佈式的一致性問題,出現了不少一致性協議和算法,好比二階段提交協議,三階段提交協議和 Paxos 算法
在異步通訊場景,即便只有一個進程失敗了,也沒有任何算法能保證非失敗進程可以達到一致性。
異步通訊與同步通訊的最大區別是沒有時鐘、不能時間同步、不能使用超時、不能探測失敗、消息可任意延遲、消息可亂序
分佈式事務用於在分佈式系統中保證不一樣節點之間的數據一致性,一般會涉及到多個數據庫。分佈式事務處理的關鍵是必須有一種方法能夠知道事務在任何地方所作的全部動做,提交或回滾事務的決定必須產生統一的結果(所有提交或所有回滾)。
DRDA: Distributed Relational Database Architecture,分佈式關係數據庫架構
XA 規範是 X/Open 組織(即如今的 Open Group) 關於分佈式事務處理 (DTP) 模型的處理規範。
DTP 模型包括應用程序 AP、事務管理器 TM、資源管理器 RM、通訊資源管理器 CRM 四部分。常見的事務管理器 TM 是交易中間件,常見的資源管理器 RM 是數據庫,常見的通訊資源管理器 CRM 是消息中間件。交易中間件是必需的,由它通知和協調相關數據庫的提交或回滾。
規範描述了全局的事務管理器與局部的資源管理器之間的接口。XA 規範的目的是容許的多個資源(如數據庫,應用服務器,消息隊列,等等)在同一事務中訪問,這樣可使 ACID 屬性跨越應用程序而保持有效。
XA 使用兩階段提交或三階段提交來保證全部資源同時提交或回滾任何特定的事務
當一個事務跨越多個節點時,爲了保持事務的 ACID 特性,須要引入一個做爲協調者的組件來統一掌控全部節點(稱做參與者)的操做結果並最終指示這些節點是否要把操做結果進行真正的提交。因此兩階段提交 (Two-phase Commit) 的算法思路能夠歸納爲: 參與者將操做成敗通知協調者,再由協調者根據全部參與者的反饋情報決定各參與者是否要提交操做仍是停止操做。
兩階段提交須要的條件:
兩個階段分別爲:
第一階段也被稱做投票階段,即各參與者投票是否要繼續接下來的提交操做
無論最後結果如何,第二階段都會結束當前事務
一、同步阻塞問題。執行過程當中,全部參與節點都是事務阻塞型的。當參與者佔有公共資源時,其餘第三方節點訪問公共資源都將處於阻塞狀態
二、單點故障。因爲協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤爲在第二階段,協調者發生故障,那麼全部的參與者還都處於鎖定事務資源的狀態中,而沒法繼續完成事務操做。(若是是協調者掛掉,能夠從新選舉一個協調者,可是沒法解決由於協調者宕機致使的參與者處於阻塞狀態的問題)
三、數據不一致。在第二階段中,當協調者向參與者發送 commit 請求以後,發生了局部網絡異常或者在發送 commit 請求過程當中協調者發生了故障,這會致使只有一部分參與者接受到了 commit 請求。而在這部分參與者接到 commit 請求以後就會執行 commit 操做。可是其餘部分未接到 commit 請求的機器則沒法執行事務提交,因而整個分佈式系統便出現了數據不一致的現象
四、二階段提交存在一個沒法解決的問題:
對於現有模型,可能會出現的錯誤和相應的措施以下
關於第三個問題的詳細描述以下:
協調者掛了,RM3 也掛了,此時分兩種狀況,RM3 是否執行了最後的事務操做:
最後這個問題就是 2PC 沒法解決的問題,但 3PC 能夠必定程度上解決
三階段提交 (Three-phase Commit) 是針對兩階段缺點而設計的改進型,相比較兩階段提交,作出如下兩點改動:
三個階段分爲:
此圖中若是某條 PreCommit 消息未到達或者超時,RM 應該中斷本身本地的事務,就跟下圖中 Abort 超時同樣
根據狀況分爲兩種情形:
圖中 RM3 在第二階段未正常響應 ACK,可能有以下狀況:
在第三階段,若是參與者沒法及時接收到來自協調者的 DoCommit 或者 Abort 請求時,會在等待超時以後,會繼續進行事務的提交
這麼作是有必定考究的,由於能進入第三階段,說明協調者確定在第二階段發起了 PreCommit 請求,而發起 PreCommit 請求的前提是第一階段全部參與者都響應了 Yes,這代表全部參與者當時的狀態都是樂觀的,那麼第三階段參與者就算沒有按時收到來自協調者的 DoCommit 請求,也繼續完成本地事務的提交,這樣完成全局事務的可能性仍是很大的,這一點是針對 2PC 數據不一致問題的
可是這一點也會形成 3PC 的一致性缺陷: 若是此時是協調者對某個 RM 發出的 Abort 請求超時,而那個 RM 繼續完成本地事務的提交,這就會形成與其餘進行回滾操做的節點數據不一致(這種狀況機率較小)
對應 2PC 的缺陷,咱們能夠看到 3PC 解決了很多問題,一方面默認的超時機制能夠避免單點故障形成的資源長久阻塞的問題;另外一方面狀態確認和默認超時提交也能夠解決 2PC 的數據不一致問題(雖然這會形成 3PC 本身的不一致問題,可是由於 3PC 的機制,這種機率更小)
至於前面提到的 2PC 沒法解決的問題,3PC 又是怎麼解決的呢?
咱們能夠回想 2PC 的問題,衝突的條件就是 RM3 第一階段投了反對票,而這件事只有原協調者知道,掛掉的二者執行了回滾操做,而新協調者和正常節點會執行提交操做;可是 3PC 將準備階段分爲兩步能夠確保最終事務操做以前,你們都知道投票結果,描述以下:
其實只要沒有執行事務最終的提交或者回滾都不影響最終結果,只要後面 RM3 恢復後查詢協調者並執行相同的操做便可
這時候新協調者出現後,只要查看正常節點的狀態就能夠知道發送提交仍是回滾指令: 若是都是 Commited 或者 PreCommit 狀態,說明第一輪投票結果都是 Yes,不然不可能進入 PreCommit 狀態,因此新協調者發送提交指令便可;若是存在節點的狀態是 Cancel,說明第一輪投票結果有反對票,那麼新協調者發送回滾指令便可。可能這裏會有個疑問,講 DoCommit 的時候咱們說過第二階段參與者的 ACK 可能沒法正常響應協調者,若是是 RM3 第一輪投了支持票後面進入 PreCommit 狀態時沒有把 ACK 正常響應給協調者,所以協調者發送了 Abort 指令給 RM3 後掛了,RM3 收到指令後也掛了,此時仍是會形成 RM3 回滾,而新協調者和正常節點執行提交的情況,這裏其實 3PC 好像也無法解決,可是這種狀況的機率你能夠估算一下,原本協調者發送指令掛了而後某些參與者執行後也掛了的機率自己就低了,還要知足掛的協調者在投完支持票後響應超時引發協調者發送 Abort 指令的機率,那就更小了
咱們用一個實際生活的例子來講明並理解這個過程:
假設協調者是牧師,而參與者是一男一女,他們來到教堂單獨跟牧師見面並傳達是否想跟另外一方創建更深的關係的信息
第一步男女雙方給牧師遞了小紙條,上面寫着是否想跟另外一方創建更深的關係,而且各自準備好了信物 (Undo&Redo)
第二步牧師看過以後,若是雙方都寫「是」,那麼告知雙方交換信物表示能夠繼續深交;若是有一方寫「否」,那麼告知雙方分手吧,信物也撤了吧
可是這裏 2PC 沒法解決一個問題: 假如男方寫的紙條信息是「否」,而牧師看過以後先告訴男方你把信物撤了吧,大家不合適,可是牧師緊接着心臟病犯了住院了,而男方收到消息後也撤了信物準備分手,但是男方忽然被人打了住院昏迷;新牧師出現,繼續詢問女方的意見,由於不知道男方的意見,他們可能會促成一樁不美滿的關係
第一步男女雙方仍是遞了小紙條,表示本身的意願
第二步牧師看過以後,若是雙方都寫「是」,那麼先告知雙方準備信物;若是有一方寫「否」,那麼告知雙方不用準備信物了;雙方收到消息後再回應說本身知道了
第三步牧師確認雙方的迴應後,告知雙方最後是否在一塊兒,是否交換信物
在這裏假如第三步牧師也是先告知男方後突發心臟病住院,而男方也是收到消息後被打昏迷,此時新牧師出現後能夠查看女方是否準備了信物而完成最後的決定,由於假如男方本來是不一樣意,那麼第二步雙方確定是沒有準備信物的,而假如男方是贊成的,那麼雙方確定是準備了信物的,那麼新牧師能夠放心宣佈雙方能夠在一塊兒
3PC 還對雙方都引入了超時,2PC 中只有牧師沒收到消息時會取消事務,而 3PC 中若是男女雙方長時間沒有收到牧師消息後也會執行本身的決定,避免了 2PC 中一樣情形時男女雙方在這裏一直耗着(阻塞)而錯過了下一任。只不過咱們提到了若是第三步牧師是由於長時間沒有收到男方的消息時也取消了事務,雖然這時候男女雙方都是贊成的,可是仍是會被取消事務,這也可能形成新的不一致問題,可是相對來講機率就小得多了
經過上述過程可知最後不管是二階段提交仍是三階段提交都沒法完全解決分佈式的一致性問題,若是系統正常運行都能知足強一致性,可是若是出現意外仍是會致使不一致,不過能夠經過其餘手段達到一致性,好比分區數據恢復或者事務補償機制或者採用其餘一致性算法
複雜的數據恢復能夠參見 SVN 的版本控制,可能能夠自動合併,也可能會發生衝忽然後須要人工干預
簡單的數據恢復能夠參見 Mysql 的主從同步,數據能夠自動從主庫導到從庫
合併分區數據達成一致並非最困難的,更困難的是處理分區過程當中產生的錯誤。當分區操做引發錯誤,能夠經過事務補償補救錯誤,這多是人工的也多是自動的
好比 MQ 消息事務和 TCC 事務協議就是一種補償機制: