深刻理解分佈式系統的2PC和3PC

深刻理解分佈式系統的2PC和3PC

關注個人博客(http://www.hollischuang.com)的人可能都知道,我以前寫過一篇文章專門介紹了一下2PC和3PC(詳見:關於分佈式事務、兩階段提交協議、三階提交協議)。上一篇文章中主要介紹了下這兩種分佈式一致性協議的概念、具體提交流程以及優缺點。本文在上篇文章的基礎上在深刻了解下這兩種分佈式一致性協議。主要來分析下爲何2PC存在問題,爲何3PC解決了部分2PC存在的問題,以及爲何3PC還存在可能致使數據不一致的狀況網絡

對分佈式系統的概念及2PC和3PC不瞭解的朋友建議先閱讀分佈式系列文章。分佈式

協調者ide


在分佈式系統中,每個機器節點雖然都能明確的知道本身執行的事務是成功仍是失敗,可是卻沒法知道其餘分佈式節點的事務執行狀況。所以,當一個事務要跨越多個分佈式節點的時候(好比,淘寶下單流程,下單系統和庫存系統可能就是分別部署在不一樣的分佈式節點中),爲了保證該事務能夠知足ACID,就要引入一個協調者(Cooradinator)。其餘的節點被稱爲參與者(Participant)。協調者負責調度參與者的行爲,並最終決定這些參與者是否要把事務進行提交。spa

二階段提交協議(2PC)事務


二階段提交協議主要分爲來個階段:準備階段和提交階段。ip

在平常生活中實際上是有不少事都是這種二階段提交的,好比西方婚禮中就常常出現這種場景:ci

牧師:"你願意娶這個女人嗎?愛她、忠誠於她,不管她貧困、患病或者殘疾,直至死亡。Doyou(你願意嗎)?"資源

新郎:"Ido(我願意)!"部署

牧師:"你願意嫁給這個男人嗎?愛他、忠誠於他,不管他貧困、患病或者殘疾,直至死亡。Doyou(你願意嗎)?"get

新娘:"Ido(我願意)!"

牧師:如今請大家面向對方,握住對方的雙手,做爲妻子和丈夫向對方宣告誓言。

新郎:我——某某某,全心全意娶你作個人妻子,不管是順境或逆境,富裕或貧窮,健康或疾病,快樂或憂愁,我都將毫無保留地愛你,我將努力去理解你,完徹底全信任你。咱們將成爲一個總體,互爲彼此的一部分,咱們將一塊兒面對人生的一切,去分享咱們的夢想,做爲平等的忠實伴侶,度過從此的一輩子。

新娘:我全心全意嫁給你做爲你的妻子,不管是順境或逆境,富裕或貧窮,健康或疾病,快樂或憂愁,我都將毫無保留的愛你,我將努力去理解你,完徹底全信任你,咱們將成爲一個總體,互爲彼此的一部分,咱們將一塊兒面對人生的一切,去分享咱們的夢想,做爲平等的忠實伴侶,度過從此的一輩子。
上面這個比較經典的橋段就是一個典型的二階段提交過程。

首先協調者(牧師)會詢問兩個參與者(二位新人)是否能執行事務提交操做(願意結婚)。若是兩個參與者可以執行事務的提交,先執行事務操做,而後返回YES,若是沒有成功執行事務操做,就返回NO。

當協調者接收到全部的參與者的反饋以後,開始進入事務提交階段。若是全部參與者都返回YES,那就發送COMMIT請求,若是有一我的返回NO,那就返送roolback請求。

值得注意的是,二階段提交協議的第一階段準備階段不只僅是回答YES or NO,仍是要執行事務操做的,只是執行完事務操做,並無進行commit仍是roolback。和上面的結婚例子不太同樣。若是非要舉例的話能夠理解爲男女雙方交換定情信物的過程。信物一旦交給對方了,這個信物就不能挪做他用了。也就是說,一旦事務執行以後,在沒有執行commit或者roolback以前,資源是被鎖定的。這會形成阻塞。

2PC存在的問題

下面咱們來分析下2PC存在的問題。

這裏暫且不談2PC存在的同步阻塞、單點問題、腦裂等問題(上篇文章中有具體介紹),咱們只討論下數據一致性問題。做爲一個分佈式的一致性協議,咱們主要關注他可能帶來的一致性問題的。

2PC在執行過程當中可能發生協調者或者參與者忽然宕機的狀況,在不一樣時期宕機可能有不一樣的現象。

狀況一:協調者掛了,參與者沒掛

這種狀況其實比較好解決,只要找一個協調者的替代者。當他成爲新的協調者的時候,詢問全部參與者的最後那條事務的執行狀況,他就能夠知道是應該作什麼樣的操做了。因此,這種狀況不會致使數據不一致。

狀況二:參與者掛了,協調者沒掛

這種狀況其實也比較好解決。若是協調者掛了。那麼以後的事情有兩種狀況:

  • 第一個是掛了就掛了,沒有再恢復。那就掛了唄,反正不會致使數據一致性問題。

  • 第二個是掛了以後又恢復了,這時若是他有未執行完的事務操做,直接取消掉,而後詢問協調者目前我應該怎麼作,協調者就會比對本身的事務執行記錄和該參與者的事務執行記錄,告訴他應該怎麼作來保持數據的一致性。

狀況三:參與者掛了,協調者也掛了

這種狀況比較複雜,咱們分狀況討論。

  • 協調者和參與者在第一階段掛了。

  • 因爲這時尚未執行commit操做,新選出來的協調者能夠詢問各個參與者的狀況,再決定是進行commit仍是roolback。由於尚未commit,因此不會致使數據一致性問題。
  • 第二階段協調者和參與者掛了,掛了的這個參與者在掛以前並無接收到協調者的指令,或者接收到指令以後還沒來的及作commit或者roolback操做。

  • 這種狀況下,當新的協調者被選出來以後,他一樣是詢問全部的參與者的狀況。只要有機器執行了abort(roolback)操做或者第一階段返回的信息是No的話,那就直接執行roolback操做。若是沒有人執行abort操做,可是有機器執行了commit操做,那麼就直接執行commit操做。這樣,當掛掉的參與者恢復以後,只要按照協調者的指示進行事務的commit仍是roolback操做就能夠了。由於掛掉的機器並無作commit或者roolback操做,而沒有掛掉的機器們和新的協調者又執行了一樣的操做,那麼這種狀況不會致使數據不一致現象。
  • 第二階段協調者和參與者掛了,掛了的這個參與者在掛以前已經執行了操做。可是因爲他掛了,沒有人知道他執行了什麼操做。

  • 這種狀況下,新的協調者被選出來以後,若是他想負起協調者的責任的話他就只能按照以前那種狀況來執行commit或者roolback操做。這樣新的協調者和全部沒掛掉的參與者就保持了數據的一致性,咱們假定他們執行了commit。可是,這個時候,那個掛掉的參與者恢復了怎麼辦,由於他以前已經執行完了以前的事務,若是他執行的是commit那還好,和其餘的機器保持一致了,萬一他執行的是roolback操做那?這不就致使數據的不一致性了麼?雖然這個時候能夠再經過手段讓他和協調者通訊,再想辦法把數據搞成一致的,可是,這段時間內他的數據狀態已是不一致的了!
    因此,2PC協議中,若是出現協調者和參與者都掛了的狀況,有可能致使數據不一致。

爲了解決這個問題,衍生除了3PC。咱們接下來看看3PC是如何解決這個問題的。

三階段提交協議(3PC)


3PC最關鍵要解決的就是協調者和參與者同時掛掉的問題,因此3PC把2PC的準備階段再次一分爲二,這樣三階段提交就有CanCommit、PreCommit、DoCommit三個階段。在第一階段,只是詢問全部參與者是否可能夠執行事務操做,並不在本階段執行事務操做。當協調者收到全部的參與者都返回YES時,在第二階段才執行事務操做,而後在第三階段在執行commit或者rollback。

這裏再舉一個生活中相似三階段提交的例子:

班長要組織全班同窗聚餐,因爲你們畢業多年,因此要逐個打電話敲定時間,時間初定10.1日。而後開始逐個打電話。

班長:小A,咱們想定在10.1號聚會,你有時間嘛?有時間你就說YES,沒有你就說NO,而後我還會再去問其餘人,具體時間地點我會再通知你,這段時間你可先去幹你本身的事兒,不用一直等着我。(協調者詢問事務是否能夠執行,這一步不會鎖定資源)

小A:好的,我有時間。(參與者反饋)

班長:小B,咱們想定在10.1號聚會......不用一直等我。

班長收集完你們的時間狀況了,一看你們都有時間,那麼就再次通知你們。(協調者接收到全部YES指令)

班長:小A,咱們肯定了10.1號聚餐,你要把這一天的時間空出來,這一天你不能再安排其餘的事兒了。而後我會逐個通知其餘同窗,通知完以後我會再來和你確認一下,還有啊,若是我沒有特地給你打電話,你就10.1號那天來聚餐就好了。對了,你肯定能來是吧?(協調者發送事務執行指令,這一步鎖住資源。若是因爲網絡緣由參與者在後面沒有收到協調者的命令,他也會執行commit)

小A順手在本身的日曆上把10.1號這一天圈上了,而後跟班長說,我能夠去。(參與者執行事務操做,反饋狀態)

班長:小B,咱們以爲了10.1號聚餐......你就10.1號那天來聚餐就好了。

班長通知完一圈以後。全部同窗都跟他說:"我已經把10.1號這天空出來了"。因而,他在10.1號這一天又挨個打了一遍電話告訴他們:嘿,如今大家能夠出門拉。。。。(協調者收到全部參與者的ACK響應,通知全部參與者執行事務的commit)

小A,小B:我已經出門拉。(執行commit操做,反饋狀態)

3PC爲何比2PC好?

直接分析協調者和參與者都掛的狀況。

  • 第二階段協調者和參與者掛了,掛了的這個參與者在掛以前已經執行了操做。可是因爲他掛了,沒有人知道他執行了什麼操做。

  • 這種狀況下,當新的協調者被選出來以後,他一樣是詢問全部的參與者的狀況來以爲是commit仍是roolback。這看上去和二階段提交同樣啊?他是怎麼解決一致性問題的呢?

  • 看上去和二階段提交的那種數據不一致的狀況的現象是同樣的,但仔細分析全部參與者的狀態的話就會發現其實並不同。咱們假設掛掉的那臺參與者執行的操做是commit。那麼其餘沒掛的操做者的狀態應該是什麼?他們的狀態要麼是prepare-commit要麼是commit。由於3PC的第三階段一旦有機器執行了commit,那必然第一階段你們都是贊成commit。因此,這時,新選舉出來的協調者一旦發現未掛掉的參與者中有人處於commit狀態或者是prepare-commit的話,那就執行commit操做。不然就執行rollback操做。這樣掛掉的參與者恢復以後就能和其餘機器保持數據一致性了。(爲了簡單的讓你們理解,筆者這裏簡化了新選舉出來的協調者執行操做的具體細節,真實狀況比我描述的要複雜)

簡單歸納一下就是,若是掛掉的那臺機器已經執行了commit,那麼協調者能夠從全部未掛掉的參與者的狀態中分析出來,並執行commit。若是掛掉的那個參與者執行了rollback,那麼協調者和其餘的參與者執行的確定也是rollback操做。

因此,再多引入一個階段以後,3PC解決了2PC中存在的那種因爲協調者和參與者同時掛掉有可能致使的數據一致性問題。

3PC存在的問題

在doCommit階段,若是參與者沒法及時接收到來自協調者的doCommit或者rebort請求時,會在等待超時以後,會繼續進行事務的提交。

因此,因爲網絡緣由,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時以後執行了commit操做。這樣就和其餘接到abort命令並執行回滾的參與者之間存在數據不一致的狀況。

參考資料


2PC和3PC一點理解

再談2PC和3PC

相關文章
相關標籤/搜索