簡書上傳不了 svg 格式的圖片嗎?! 圖文可以去原文看 ??
分布式系統(tǒng)理論
CAP 定理
CAP 定理指出對于一個分布式系統(tǒng)來說,不可能同時滿足以下三點:
- 一致性 (Consistence): 等同于所有節(jié)點訪問同一份最新的數(shù)據(jù)副本 (強一致性)
- 可用性 (Availability): 每次請求都能獲取到非錯的響應(yīng),但是不保證獲取的數(shù)據(jù)為最新數(shù)據(jù)
- 分區(qū)容錯性 (Partition tolerance): 系統(tǒng)如果不能在時限內(nèi)達成數(shù)據(jù)一致性,就意味著發(fā)生了分區(qū)的情況,此時必須在 C 和 A 之間做出取舍
一個分布式系統(tǒng)里面,節(jié)點組成的網(wǎng)絡(luò)本來應(yīng)該是連通的。然而可能因為一些故障或者延時,使得有些節(jié)點之間不連通了,整個網(wǎng)絡(luò)就分成了幾塊區(qū)域。數(shù)據(jù)就散布在了這些不連通的區(qū)域中,這就叫分區(qū)。當你一個數(shù)據(jù)項只在一個節(jié)點中保存,那么分區(qū)出現(xiàn)后,和這個節(jié)點不連通的部分就訪問不到這個數(shù)據(jù)了。這時分區(qū)就是無法容忍的。提高分區(qū)容忍性的辦法就是將一個數(shù)據(jù)項復(fù)制到多個節(jié)點上,那么出現(xiàn)分區(qū)之后,這一數(shù)據(jù)項就可能分布到各個區(qū)里,容忍性就提高了。然而,要把數(shù)據(jù)復(fù)制到多個節(jié)點,就會帶來一致性的問題,就是多個節(jié)點上面的數(shù)據(jù)可能是不一致的。要保證一致,每次寫操作就都要等待全部節(jié)點寫成功,而這等待又會帶來可用性的問題。總的來說就是,數(shù)據(jù)存在的節(jié)點越多,分區(qū)容忍性越高,但要復(fù)制更新的數(shù)據(jù)就越多,一致性就越難保證。為了保證一致性,更新所有節(jié)點數(shù)據(jù)所需要的時間就越長,可用性就會降低 -- 來自知乎鄔江的回答
CAP 理論實際想表達的是任何分布式系統(tǒng)不能同時滿足強一致性、高可用性和較好的分區(qū)容錯性
[圖片上傳失敗...(image-bb9105-1545273484228)]
RDBMS: Relational Database Management System,關(guān)系型數(shù)據(jù)庫管理系統(tǒng)
由 CAP 定理可知數(shù)據(jù)庫的設(shè)計需要權(quán)衡取舍,所以可以把數(shù)據(jù)庫大致分為三類:
- CA: 單點集群,滿足一致性,可用性的系統(tǒng),通常在可擴展性上不太強大
- CP: 滿足一致性,分區(qū)容忍性的系統(tǒng),通常性能不是特別高
- AP: 滿足可用性,分區(qū)容忍性的系統(tǒng),通常可能對一致性要求低一些
分布式和集群的區(qū)別:
分布式: 不同的多臺服務(wù)器上面部署不同的服務(wù)模塊,他們之間通過 Rpc/HTTP 等方式進行通信和調(diào)用,對外提供服務(wù)和組內(nèi)協(xié)作
集群: 不同的多臺服務(wù)器上面部署相同的服務(wù)模塊,通過分布式調(diào)度軟件進行統(tǒng)一的調(diào)度,對外提供服務(wù)和訪問
ACID 和 BASE
ACID
ACID 指的是傳統(tǒng)數(shù)據(jù)庫中事務(wù)操作所具備的四個特性:
- 原子性 (Atomicity): 一個事務(wù) (transaction) 中的所有操作作為一個基本單元,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣
- 一致性 (Consistency): 在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。一個事務(wù)能夠正確地將數(shù)據(jù)庫從一個一致性狀態(tài)變換為另一個一致性狀態(tài)
- 隔離性 (Isolation): 也可以稱作獨立性,數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級別,包括讀未提交 (Read uncommitted)、讀提交 (read committed)、可重復(fù)讀 (repeatable read) 和串行化 (Serializable)
- 持久性 (Durability): 事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失
BASE
BASE 理論是對 CAP 理論的延伸,核心思想是雖然無法做到強一致性 (Strong Consistency),但可以采用適合的方式達到最終一致性 (Eventual Consitency)
BASE 包含三部分:
- 基本可用 (Basically Available): 指分布式系統(tǒng)在出現(xiàn)故障的時候,允許損失部分可用性,保證核心可用
- 軟狀態(tài) (Soft State): 指允許系統(tǒng)存在中間狀態(tài),而該中間狀態(tài)不會影響系統(tǒng)整體可用性。分布式存儲中一般一份數(shù)據(jù)至少會有三個副本,允許不同節(jié)點間副本同步的延時就是軟狀態(tài)的體現(xiàn)。mysql replication 的異步復(fù)制也是一種體現(xiàn)
- 最終一致性 (Eventual Consistency): 指系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過一定時間后,最終能夠達到一致的狀態(tài)。最終一致性是弱一致性的一種特殊情況
兩者區(qū)別
ACID 隸屬于 CA,是傳統(tǒng)數(shù)據(jù)庫常用的設(shè)計理念,追求強一致性模型
BASE 隸屬于 AP,支持的是大型分布式系統(tǒng),提出通過犧牲強一致性獲得高可用性
但在實際的分布式場景中,不同業(yè)務(wù)單元和組件對數(shù)據(jù)一致性的要求是不同的,因此在具體的分布式系統(tǒng)架構(gòu)設(shè)計過程中,ACID 特性與 BASE 理論往往會結(jié)合在一起使用。比如整體滿足 BASE,局部滿足 ACID。
一致性模型
- 強一致性: 當更新操作完成之后,任何多個后續(xù)進程或者線程的訪問都會返回最新的更新過的值。這種是對用戶最友好的,就是用戶上一次寫什么,下一次就保證能讀到什么。但是這種實現(xiàn)對性能影響較大,因為這意味著,只要上次的操作沒有處理完,就不能讓用戶讀取數(shù)據(jù)
- 弱一致性: 系統(tǒng)并不保證進程或者線程的訪問都會返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)寫入成功之后,不承諾立即可以讀到最新寫入的值,也不會具體的承諾多久之后可以讀到。但會盡可能保證在某個時間級別(比如秒級別)之后,可以讓數(shù)據(jù)達到一致性狀態(tài)
- 最終一致性: 弱一致性的特定形式。系統(tǒng)保證在沒有后續(xù)更新的前提下,系統(tǒng)最終返回上一次更新操作的值。在沒有故障發(fā)生的前提下,不一致窗口的時間主要受通信延遲,系統(tǒng)負載和復(fù)制副本的個數(shù)影響。DNS 是一個典型的最終一致性系統(tǒng)
- 因果一致性: 如果 A 進程在更新之后向 B 進程通知更新的完成,那么 B 的訪問操作將會返回更新的值。如果沒有因果關(guān)系的 C 進程將會遵循最終一致性的規(guī)則
- 讀己所寫一致性: 因果一致性的特定形式。一個進程總可以讀到自己更新的數(shù)據(jù)
- 會話一致性: 讀己所寫一致性的特定形式。進程在訪問存儲系統(tǒng)同一個會話內(nèi),系統(tǒng)保證該進程讀己之所寫
- 單調(diào)讀一致性: 如果一個進程已經(jīng)讀取到一個特定值,那么該進程不會讀取到該值舊版本的任何值
- 單調(diào)寫一致性: 系統(tǒng)保證對同一個進程的寫操作串行化
- 最終一致性: 弱一致性的特定形式。系統(tǒng)保證在沒有后續(xù)更新的前提下,系統(tǒng)最終返回上一次更新操作的值。在沒有故障發(fā)生的前提下,不一致窗口的時間主要受通信延遲,系統(tǒng)負載和復(fù)制副本的個數(shù)影響。DNS 是一個典型的最終一致性系統(tǒng)
上述最終一致性的不同方式可以進行組合,例如單調(diào)讀一致性和讀己之所寫一致性就可以組合實現(xiàn)。并且從實踐的角度來看,這兩者的組合,讀取自己更新的數(shù)據(jù),和一旦讀取到最新的版本不會再讀取舊版本,對于此架構(gòu)上的程序開發(fā)來說,會少很多額外的煩惱。
從服務(wù)端角度,如何盡快將更新后的數(shù)據(jù)分布到整個系統(tǒng),降低達到最終一致性的時間窗口,是提高系統(tǒng)的可用度和用戶體驗非常重要的方面。
為了解決分布式的一致性問題,出現(xiàn)了很多一致性協(xié)議和算法,比如二階段提交協(xié)議,三階段提交協(xié)議和 Paxos 算法
FLP 不可能定理
在異步通信場景,即使只有一個進程失敗了,也沒有任何算法能保證非失敗進程能夠達到一致性。
異步通信與同步通信的最大區(qū)別是沒有時鐘、不能時間同步、不能使用超時、不能探測失敗、消息可任意延遲、消息可亂序
分布式事務(wù)
分布式事務(wù)用于在分布式系統(tǒng)中保證不同節(jié)點之間的數(shù)據(jù)一致性,通常會涉及到多個數(shù)據(jù)庫。分布式事務(wù)處理的關(guān)鍵是必須有一種方法可以知道事務(wù)在任何地方所做的所有動作,提交或回滾事務(wù)的決定必須產(chǎn)生統(tǒng)一的結(jié)果(全部提交或全部回滾)。
DRDA: Distributed Relational Database Architecture,分布式關(guān)系數(shù)據(jù)庫架構(gòu)
XA 規(guī)范
XA 規(guī)范是 X/Open 組織(即現(xiàn)在的 Open Group) 關(guān)于分布式事務(wù)處理 (DTP) 模型的處理規(guī)范。
DTP 模型包括應(yīng)用程序 AP、事務(wù)管理器 TM、資源管理器 RM、通信資源管理器 CRM 四部分。常見的事務(wù)管理器 TM 是交易中間件,常見的資源管理器 RM 是數(shù)據(jù)庫,常見的通信資源管理器 CRM 是消息中間件。交易中間件是必需的,由它通知和協(xié)調(diào)相關(guān)數(shù)據(jù)庫的提交或回滾。
規(guī)范描述了全局的事務(wù)管理器與局部的資源管理器之間的接口。XA 規(guī)范的目的是允許的多個資源(如數(shù)據(jù)庫,應(yīng)用服務(wù)器,消息隊列,等等)在同一事務(wù)中訪問,這樣可以使 ACID 屬性跨越應(yīng)用程序而保持有效。
XA 使用兩階段提交或三階段提交來保證所有資源同時提交或回滾任何特定的事務(wù)
兩階段提交-2PC
當一個事務(wù)跨越多個節(jié)點時,為了保持事務(wù)的 ACID 特性,需要引入一個作為協(xié)調(diào)者的組件來統(tǒng)一掌控所有節(jié)點(稱作參與者)的操作結(jié)果并最終指示這些節(jié)點是否要把操作結(jié)果進行真正的提交。所以兩階段提交 (Two-phase Commit) 的算法思路可以概括為: 參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。
兩階段提交需要的條件:
- 分布式系統(tǒng)中,存在一個節(jié)點作為協(xié)調(diào)者 (Coordinator),其他節(jié)點作為參與者 (Cohorts),且節(jié)點之間可以進行網(wǎng)絡(luò)通信
- 所有節(jié)點都采用預(yù)寫式日志,且日志被寫入后即被保持在可靠的存儲設(shè)備上,即使節(jié)點損壞不會導(dǎo)致日志數(shù)據(jù)的消失
- 所有節(jié)點不會永久性損壞,即使損壞后仍然可以恢復(fù)
兩個階段分別為:
- 準備階段(投票階段)
- 提交階段(執(zhí)行階段)
準備階段
- 事務(wù)協(xié)調(diào)者(事務(wù)管理器)給每個參與者(資源管理器)發(fā)送 Prepare 消息,詢問是否可以執(zhí)行提交操作,并開始等待各參與者節(jié)點的響應(yīng)
- 參與者執(zhí)行事務(wù)操作,并將 Undo 信息和 Redo 信息寫入日志
- 各參與者節(jié)點響應(yīng)協(xié)調(diào)者節(jié)點發(fā)起的詢問。如果參與者節(jié)點的事務(wù)操作實際執(zhí)行成功,則它返回一個"同意" (agreement) 消息;如果參與者節(jié)點的事務(wù)操作實際執(zhí)行失敗,則它返回一個"中止" (Abort) 消息
[圖片上傳失敗...(image-41b4a6-1545273484228)]
第一階段也被稱作投票階段,即各參與者投票是否要繼續(xù)接下來的提交操作
提交階段
- 當協(xié)調(diào)者節(jié)點從所有參與者節(jié)點獲得的響應(yīng)消息都為"同意"時
- 協(xié)調(diào)者節(jié)點向所有參與者節(jié)點發(fā)出"正式提交"的請求
- 參與者節(jié)點正式完成操作,并釋放在整個事務(wù)期間內(nèi)占用的資源
- 參與者節(jié)點向協(xié)調(diào)者節(jié)點發(fā)送"完成"消息
- 協(xié)調(diào)者節(jié)點收到所有參與者節(jié)點反饋的"完成"消息后,完成事務(wù)
[圖片上傳失敗...(image-9f15ac-1545273484228)]
- 如果任一參與者節(jié)點在第一階段返回的響應(yīng)消息為"中止",或者協(xié)調(diào)者節(jié)點在第一階段的詢問超時之前無法獲取所有參與者節(jié)點的響應(yīng)消息時
- 協(xié)調(diào)者節(jié)點向所有參與者節(jié)點發(fā)出"回滾操作"的請求
- 參與者節(jié)點利用之前寫入的 Undo 信息執(zhí)行回滾,并釋放在整個事務(wù)期間內(nèi)占用的資源
- 參與者節(jié)點向協(xié)調(diào)者節(jié)點發(fā)送"回滾完成"消息
- 協(xié)調(diào)者節(jié)點收到所有參與者節(jié)點反饋的"回滾完成"消息后,取消事務(wù)
[圖片上傳失敗...(image-181417-1545273484228)]
不管最后結(jié)果如何,第二階段都會結(jié)束當前事務(wù)
缺陷
1、同步阻塞問題。執(zhí)行過程中,所有參與節(jié)點都是事務(wù)阻塞型的。當參與者占有公共資源時,其他第三方節(jié)點訪問公共資源都將處于阻塞狀態(tài)
2、單點故障。由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障。參與者會一直阻塞下去。尤其在第二階段,協(xié)調(diào)者發(fā)生故障,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作。(如果是協(xié)調(diào)者掛掉,可以重新選舉一個協(xié)調(diào)者,但是無法解決因為協(xié)調(diào)者宕機導(dǎo)致的參與者處于阻塞狀態(tài)的問題)
3、數(shù)據(jù)不一致。在第二階段中,當協(xié)調(diào)者向參與者發(fā)送 commit 請求之后,發(fā)生了局部網(wǎng)絡(luò)異常或者在發(fā)送 commit 請求過程中協(xié)調(diào)者發(fā)生了故障,這會導(dǎo)致只有一部分參與者接受到了 commit 請求。而在這部分參與者接到 commit 請求之后就會執(zhí)行 commit 操作。但是其他部分未接到 commit 請求的機器則無法執(zhí)行事務(wù)提交,于是整個分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)不一致的現(xiàn)象
4、二階段提交存在一個無法解決的問題:
對于現(xiàn)有模型,可能會出現(xiàn)的錯誤和相應(yīng)的措施如下
- 協(xié)調(diào)者出錯,參與者不出錯
- 可以通過快速創(chuàng)建一個新的協(xié)調(diào)者來解決(或者原本就有備用協(xié)調(diào)者)
- 協(xié)調(diào)者不出錯,參與者出錯
- 如果參與者是第一階段一開始就掛了,那么投票失敗,協(xié)調(diào)者取消事務(wù)即可
- 如果參與者是投完票才掛的,那么投票依舊有效,協(xié)調(diào)者會下達最終的事務(wù)操作指令,正常節(jié)點都會完成最后的事務(wù)提交或回滾,而掛掉的參與者恢復(fù)后只要詢問協(xié)調(diào)者并執(zhí)行相同的操作即可
- 協(xié)調(diào)者出錯,參與者也出錯
- 這種情況就比較復(fù)雜了,需要單獨講
關(guān)于第三個問題的詳細描述如下:
[圖片上傳失敗...(image-c43b4a-1545273484228)]
協(xié)調(diào)者掛了,RM3 也掛了,此時分兩種情況,RM3 是否執(zhí)行了最后的事務(wù)操作:
- RM3 掛之前不管收沒收到指令,只要沒有執(zhí)行事務(wù)操作,都是不影響最終一致性的,因為 RM3 掛了但它的事務(wù)尚未作出最后的提交或回滾時,新的協(xié)調(diào)者和其他正常節(jié)點不管最后是做了提交還是回滾,只要 RM3 恢復(fù)后詢問新協(xié)調(diào)者采取相同的操作即可保證全局一致
- 嚴重的問題是掛掉的 RM3 掛之前執(zhí)行了事務(wù)的最終操作:
- 協(xié)調(diào)者第二階段發(fā)出一條指令后掛了,而 RM3 收到這條指令后對事物做了操作后也跟著掛了,等新的協(xié)調(diào)者出現(xiàn)時,沒有人知道之前原協(xié)調(diào)者發(fā)送的是 Commit 還是 Rollback,也不清楚 RM3 是執(zhí)行了提交還是回滾;新的協(xié)調(diào)者出現(xiàn)后會詢問各節(jié)點狀態(tài),如果有節(jié)點回復(fù)的是 No,那么發(fā)送回滾指令,如果各節(jié)點都回復(fù) Yes,則發(fā)送提交指令;比如上圖中新協(xié)調(diào)者和其他正常節(jié)點應(yīng)該會投票成功然后執(zhí)行了 Commit 指令,而 RM3 恢復(fù)正常后,整體是否一致很難確定,因為 RM3 可能在第一階段回復(fù)的是 Abort,然后原協(xié)調(diào)者發(fā)送了 Rollback,掛之前 RM3 已經(jīng)回滾,那么此時全局就不一致了(此時需要不一致的 RM3 通過其他方式恢復(fù)一致,但完成之前系統(tǒng)整體是不一致的)
最后這個問題就是 2PC 無法解決的問題,但 3PC 可以一定程度上解決
三階段提交-3PC
三階段提交 (Three-phase Commit) 是針對兩階段缺點而設(shè)計的改進型,相比較兩階段提交,做出以下兩點改動:
- 引入超時機制。同時在協(xié)調(diào)者和參與者中都引入超時機制(2PC 只有協(xié)調(diào)者設(shè)置了超時機制),超時后可以默認執(zhí)行 Commit 或者 Abort,這一點可以避免事務(wù)資源長時間被阻塞
- 在第一階段和第二階段中插入一個準備階段。保證了在最后提交階段之前各參與節(jié)點的狀態(tài)是一致的
三個階段分為:
- CanCommit
- PreCommit
- DoCommit
CanCommit
- 協(xié)調(diào)者向參與者發(fā)送 CanCommit 請求。詢問是否可以執(zhí)行事務(wù)提交操作。然后開始等待參與者的響應(yīng)
- 參與者接到 CanCommit 請求之后,正常情況下,如果其自身認為可以順利執(zhí)行事務(wù),則返回 Yes 響應(yīng),并進入預(yù)備狀態(tài)。否則反饋 No
[圖片上傳失敗...(image-1618d1-1545273484228)]
PreCommit
- 假如協(xié)調(diào)者從所有的參與者獲得的反饋都是 Yes 響應(yīng),那么就會執(zhí)行事務(wù)的預(yù)執(zhí)行:
- 發(fā)送預(yù)提交請求協(xié)調(diào)者向參與者發(fā)送 PreCommit 請求,并進入 Prepared 階段
- 事務(wù)預(yù)提交參與者接收到 PreCommit 請求后,會執(zhí)行事務(wù)操作,并將 Undo 和 Redo 信息記錄到事務(wù)日志中
- 如果參與者成功的執(zhí)行了事務(wù)操作,則返回 ACK 響應(yīng),同時開始等待最終指令
[圖片上傳失敗...(image-7bd5b9-1545273484228)]
此圖中如果某條 PreCommit 消息未到達或者超時,RM 應(yīng)該中斷自己本地的事務(wù),就跟下圖中 Abort 超時一樣
- 假如有任何一個參與者向協(xié)調(diào)者發(fā)送了 No 響應(yīng),或者等待超時之后,協(xié)調(diào)者都沒有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷:
- 發(fā)送中斷請求協(xié)調(diào)者向所有參與者發(fā)送 Abort 請求
- 參與者收到來自協(xié)調(diào)者的 Abort 請求之后(或超時之后,仍未收到協(xié)調(diào)者的請求),執(zhí)行事務(wù)的中斷
[圖片上傳失敗...(image-ea0c4f-1545273484228)]
DoCommit
根據(jù)情況分為兩種情形:
- 正常響應(yīng)后執(zhí)行提交操作完成事務(wù):
- 協(xié)調(diào)者接收到 PreCommit 階段中參與者發(fā)送的 ACK 響應(yīng),那么他將從預(yù)提交狀態(tài)進入到提交狀態(tài),并向所有參與者發(fā)送 DoCommit 請求
- 參與者接收到 DoCommit 請求之后,執(zhí)行正式的事務(wù)提交,并在完成事務(wù)提交之后釋放所有事務(wù)資源
- 事務(wù)提交完之后,向協(xié)調(diào)者發(fā)送 ACK 響應(yīng)
- 協(xié)調(diào)者接收到所有參與者的 ACK 響應(yīng)之后,完成事務(wù)
[圖片上傳失敗...(image-508d8f-1545273484228)]
- 協(xié)調(diào)者沒有接收到參與者發(fā)送的 ACK 響應(yīng)(可能是接受者發(fā)送的不是 ACK 響應(yīng),也可能響應(yīng)超時),那么就會執(zhí)行中斷事務(wù):
- 協(xié)調(diào)者向所有參與者發(fā)送 Abort 請求
- 參與者接收到 Abort 請求之后,利用其在階段二記錄的 Undo 信息來執(zhí)行事務(wù)的回滾操作,并在完成回滾之后釋放所有的事務(wù)資源。
- 參與者完成事務(wù)回滾之后,向協(xié)調(diào)者發(fā)送 ACK 消息
- 協(xié)調(diào)者接收到參與者反饋的 ACK 消息之后,結(jié)束事務(wù)
[圖片上傳失敗...(image-8ad1fa-1545273484228)]
圖中 RM3 在第二階段未正常響應(yīng) ACK,可能有如下情況:
- 比如 RM3 未正常接收 PreCommit 消息,在第二階段就取消了本地事務(wù),所以沒有返回 ACK,則第三階段接收 Abort 時并不需要做什么
- 也可能是 RM3 收到了 PreCommit 消息并執(zhí)行了事務(wù)操作,但是 ACK 消息發(fā)送超時,則第三階段接收 Abort 時也是同其他節(jié)點一樣執(zhí)行 Undo 回滾
- 如果是第二階段 RM3 掛了,如果是持久性掛了,那就掛了吧,現(xiàn)階段就不管它了,等恢復(fù)了再做數(shù)據(jù)同步;如果掛了之后又恢復(fù)了,需要詢問 TM 現(xiàn)在的事務(wù)狀態(tài)來進行判斷是否取消本地事務(wù)還是繼續(xù)完成事務(wù)
在第三階段,如果參與者無法及時接收到來自協(xié)調(diào)者的 DoCommit 或者 Abort 請求時,會在等待超時之后,會繼續(xù)進行事務(wù)的提交
這么做是有一定考究的,因為能進入第三階段,說明協(xié)調(diào)者肯定在第二階段發(fā)起了 PreCommit 請求,而發(fā)起 PreCommit 請求的前提是第一階段所有參與者都響應(yīng)了 Yes,這表明所有參與者當時的狀態(tài)都是樂觀的,那么第三階段參與者就算沒有按時收到來自協(xié)調(diào)者的 DoCommit 請求,也繼續(xù)完成本地事務(wù)的提交,這樣完成全局事務(wù)的可能性還是很大的,這一點是針對 2PC 數(shù)據(jù)不一致問題的
但是這一點也會造成 3PC 的一致性缺陷: 如果此時是協(xié)調(diào)者對某個 RM 發(fā)出的 Abort 請求超時,而那個 RM 繼續(xù)完成本地事務(wù)的提交,這就會造成與其他進行回滾操作的節(jié)點數(shù)據(jù)不一致(這種情況概率較小)
缺陷
對應(yīng) 2PC 的缺陷,我們可以看到 3PC 解決了不少問題,一方面默認的超時機制可以避免單點故障造成的資源長久阻塞的問題;另一方面狀態(tài)確認和默認超時提交也可以解決 2PC 的數(shù)據(jù)不一致問題(雖然這會造成 3PC 自己的不一致問題,但是因為 3PC 的機制,這種概率更小)
至于前面提到的 2PC 無法解決的問題,3PC 又是怎么解決的呢?
我們可以回想 2PC 的問題,沖突的條件就是 RM3 第一階段投了反對票,而這件事只有原協(xié)調(diào)者知道,掛掉的兩者執(zhí)行了回滾操作,而新協(xié)調(diào)者和正常節(jié)點會執(zhí)行提交操作;但是 3PC 將準備階段分為兩步可以確保最終事務(wù)操作之前,大家都知道投票結(jié)果,描述如下:
- 假如同樣是第二階段協(xié)調(diào)者和 RM3 掛了
[圖片上傳失敗...(image-85e40a-1545273484228)]
其實只要沒有執(zhí)行事務(wù)最終的提交或者回滾都不影響最終結(jié)果,只要后面 RM3 恢復(fù)后查詢協(xié)調(diào)者并執(zhí)行相同的操作即可
- 假如是進入第三階段協(xié)調(diào)者和 RM3 掛了,而且 RM3 已經(jīng)執(zhí)行了最終操作
[圖片上傳失敗...(image-68f35a-1545273484228)]
這時候新協(xié)調(diào)者出現(xiàn)后,只要查看正常節(jié)點的狀態(tài)就可以知道發(fā)送提交還是回滾指令: 如果都是 Commited 或者 PreCommit 狀態(tài),說明第一輪投票結(jié)果都是 Yes,否則不可能進入 PreCommit 狀態(tài),所以新協(xié)調(diào)者發(fā)送提交指令即可;如果存在節(jié)點的狀態(tài)是 Cancel,說明第一輪投票結(jié)果有反對票,那么新協(xié)調(diào)者發(fā)送回滾指令即可。可能這里會有個疑問,講 DoCommit 的時候我們說過第二階段參與者的 ACK 可能無法正常響應(yīng)協(xié)調(diào)者,如果是 RM3 第一輪投了支持票后面進入 PreCommit 狀態(tài)時沒有把 ACK 正常響應(yīng)給協(xié)調(diào)者,因此協(xié)調(diào)者發(fā)送了 Abort 指令給 RM3 后掛了,RM3 收到指令后也掛了,此時還是會造成 RM3 回滾,而新協(xié)調(diào)者和正常節(jié)點執(zhí)行提交的狀況,這里其實 3PC 好像也沒法解決,但是這種情況的概率你可以估算一下,本來協(xié)調(diào)者發(fā)送指令掛了然后某些參與者執(zhí)行后也掛了的概率本身就低了,還要滿足掛的協(xié)調(diào)者在投完支持票后響應(yīng)超時引起協(xié)調(diào)者發(fā)送 Abort 指令的概率,那就更小了
理解 2PC 和 3PC
我們用一個實際生活的例子來說明并理解這個過程:
假設(shè)協(xié)調(diào)者是牧師,而參與者是一男一女,他們來到教堂單獨跟牧師見面并傳達是否想跟另一方建立更深的關(guān)系的信息
2PC
第一步男女雙方給牧師遞了小紙條,上面寫著是否想跟另一方建立更深的關(guān)系,并且各自準備好了信物 (Undo&Redo)
第二步牧師看過之后,如果雙方都寫“是”,那么告知雙方交換信物表示可以繼續(xù)深交;如果有一方寫“否”,那么告知雙方分手吧,信物也撤了吧
但是這里 2PC 無法解決一個問題: 假如男方寫的紙條信息是“否”,而牧師看過之后先告訴男方你把信物撤了吧,你們不合適,但是牧師緊接著心臟病犯了住院了,而男方收到消息后也撤了信物準備分手,可是男方突然被人打了住院昏迷;新牧師出現(xiàn),繼續(xù)詢問女方的意見,因為不知道男方的意見,他們可能會促成一樁不美滿的關(guān)系
3PC
第一步男女雙方還是遞了小紙條,表示自己的意愿
第二步牧師看過之后,如果雙方都寫“是”,那么先告知雙方準備信物;如果有一方寫“否”,那么告知雙方不用準備信物了;雙方收到消息后再回應(yīng)說自己知道了
第三步牧師確認雙方的回應(yīng)后,告知雙方最后是否在一起,是否交換信物
在這里假如第三步牧師也是先告知男方后突發(fā)心臟病住院,而男方也是收到消息后被打昏迷,此時新牧師出現(xiàn)后可以查看女方是否準備了信物而完成最后的決定,因為假如男方原本是不同意,那么第二步雙方肯定是沒有準備信物的,而假如男方是同意的,那么雙方肯定是準備了信物的,那么新牧師可以放心宣布雙方可以在一起
3PC 還對雙方都引入了超時,2PC 中只有牧師沒收到消息時會取消事務(wù),而 3PC 中如果男女雙方長時間沒有收到牧師消息后也會執(zhí)行自己的決定,避免了 2PC 中同樣情形時男女雙方在這里一直耗著(阻塞)而錯過了下一任。只不過我們提到了如果第三步牧師是因為長時間沒有收到男方的消息時也取消了事務(wù),雖然這時候男女雙方都是同意的,但是還是會被取消事務(wù),這也可能造成新的不一致問題,但是相對來說概率就小得多了
解決不一致問題
通過上述過程可知最后無論是二階段提交還是三階段提交都無法徹底解決分布式的一致性問題,如果系統(tǒng)正常運行都能滿足強一致性,但是如果出現(xiàn)意外還是會導(dǎo)致不一致,不過可以通過其他手段達到一致性,比如分區(qū)數(shù)據(jù)恢復(fù)或者事務(wù)補償機制或者采用其他一致性算法
分區(qū)數(shù)據(jù)恢復(fù)
復(fù)雜的數(shù)據(jù)恢復(fù)可以參見 SVN 的版本控制,可能可以自動合并,也可能會發(fā)生沖突然后需要人工干預(yù)
簡單的數(shù)據(jù)恢復(fù)可以參見 Mysql 的主從同步,數(shù)據(jù)可以自動從主庫導(dǎo)到從庫
合并分區(qū)數(shù)據(jù)達成一致并不是最困難的,更困難的是處理分區(qū)過程中產(chǎn)生的錯誤。當分區(qū)操作引起錯誤,可以通過事務(wù)補償補救錯誤,這可能是人工的也可能是自動的
分區(qū)事務(wù)補償
比如 MQ 消息事務(wù)和 TCC 事務(wù)協(xié)議就是一種補償機制:
- MQ 事務(wù): 利用消息中間件來異步完成事務(wù)的后一半更新,實現(xiàn)系統(tǒng)的最終一致性
- TCC 事務(wù): TCC 是阿里巴巴提出的協(xié)議,將一個事務(wù)分為 Try、Commit、Cancel 三部分,也可以達到最終一致性
其他一致性算法
- Paxos 算法: 一種基于消息傳遞且具有高度容錯特性的一致性算法