天天看點

海量存儲之十六--一緻性和高可用專題

很久木有和大家見面了,因為部落客也需要時間來沉澱。。部落客也需要學習和思考。。

好吧,不多廢話,進入正題,今天我們談的東西是一緻性和安全性。

一緻性這個問題,非常繞,想用語言表述,難度很大,我給别人去講的時候,一般都是白闆,因為白闆有類似“動畫”的效果,能夠幫助别人了解,但使用文字,就沒有辦法了,隻好要求各位有一定的抽象思維能力,能在自己的腦袋裡模拟這種動畫吧:)

主要會聊到: 簡單的雙機兩階段送出,三階段送出,vector clock ,paxos思路,paxos改進思路,既然要闡述問題,那我們就需要先給自己畫個框框,首先來對這個問題做一個定義。

============

寫在前面,發現不少讀者都會用自己以前的2pc知識來套用文章裡面提到的2pc改。

我想說的是,在這裡的兩段送出,與大家所了解的兩段送出,有一定差別。

他是為了滿足文中提到的c問題而改過的2pc.是以能夠解決一些問題,但也會産生一些新的問題。各位一定要放棄過去對2pc的了解,一步一步的跟着文中的思路走下來,你就會發現他其實不是真正事務中所用到的2pc,而是專門為了同步和高可用改過的2pc協定。

問題描述

人們在計算機上面,經常會碰到這樣一個需求:如何能夠保證一個資料寫入到某台或某組機器上,并且計算機傳回成功,那麼無論機器是否掉電,都能夠保證資料不會丢失,并且能夠保證資料按照我寫入的順序排列呢?

面對這個問題,一般人的最常見思路就是:每次寫都必須保證磁盤寫成功才算成功就好了嘛。

沒錯,這就是單機一緻性的最好诠釋,每次寫入,都落一次磁盤,就可以保證在單機的資料安全了。

那麼有人問了,硬碟壞了怎麼辦?不是還丢了麼?沒錯啊,是以又引入了一種技術,叫做磁盤陣列(這東西,在我們目前的這個一緻性裡面不去表述,感興趣的同學可以自己去研究一下)

好像說到這,一緻性就說完了嘛。。無非也就是保證每次成功的寫入,資料不會丢失,并且按照寫入的順序排列,就可以保證資料的一緻性了。

别急,我們這才要進入正題:

如果給你更多的機器,你能做到更安全麼?

那麼,我們來看看,有了更多機器,我們能做到什麼?

以前,單機的時候,這台機器挂了,服務也就終止了,沒有任何方式能夠保證在這台機器斷電或挂了的時候,他還能服務不是?但如果有更多的機器,那麼你就會忽然發現,一台機器挂了,不是還有其他機器麼?一個機房裡面的所有機器都挂了,不是還有其他機房麼?美國被核武器爆菊了以後,不是還有中國的機房麼?地球被火星來客毀滅了,不是還有火星機房麼?

哈,排比了這麼多,其實就是想說明,在機器多了以後,人們就可以額外的追求更多的東西了,這東西就是服務的可用性,無論如何,隻要有錢,有網絡,服務就可用。怎麼樣?吸引人吧?(不過,可用性這個詞在cap理論裡面,不隻是指服務可以被通路,還有個很扯淡的屬性是延遲,因為延遲這個屬性很難被量化定義,是以我一般認為cap是比較扯淡的。。。)

好,我們現在就來重新定義一下我們要研究的問題:

尋求一種能夠保證,在給定多台計算機,并且他們互相之間由網絡互相連通,中間的資料沒有拜占庭将軍問題(資料不會被僞造)的前提下,能夠做到以下兩個特性的方法:

1)資料每次成功的寫入,資料不會丢失,并且按照寫入的順序排列

2)給定安全級别(美國被爆菊?火星人入侵?),保證服務可用性,并盡可能減少機器的消耗。

我們把這個問題簡寫為c問題,裡面有兩個子問題c1,c2.

為了闡述一下c問題,我們需要先準備一個基礎知識,這知識如此重要而簡單,以至于将伴随着每一個分布式問題而出現(以前,也說過這個問題的哦..:) )

假定有兩個人,李雷和韓梅梅,假定,李雷讓韓梅梅去把隔壁班的電燈關掉,這時候,韓梅梅可能有以下幾種回報:

1)"好了,關了"(成功)

2)"開關壞了,沒法關"(失敗)

3)

呵呵,3是什麼?韓梅梅被外星人劫持了,消失了。。于是,回報也沒有了。。(無回報)

這是一切網絡傳遞問題的核心,請好好了解哈。。。

--------------準備結束,進入正題---------------------

兩段送出改:

首先,我們來看一種最容易想到的方式,2pc變種協定。

如果我有兩台機器,那麼如何能夠保證兩台機器c問題呢?

海量存儲之十六--一緻性和高可用專題

我們假定a是協調者,那麼a将某個事件通知給b,b會有以下幾種回報:

1.成功,這個可以不表。正常狀态

2.失敗,這個是第二機率出現的事件,比如硬碟滿了?記憶體滿了?不符合某些條件?為了解決這個情況,是以我們必須讓a多一個步驟,準備,準備意味着如果b失敗,那麼a也自然不應該繼續進行,應該将a的所有已經做得修改復原,然後通知用戶端:錯誤啦。

是以,我們為了能做到能夠讓a應付b失敗的這個情況,需要将同步協定設計為:

preparea -> commit b -> commit a.

使用這個協定,就可以保證b就算出現了某些異常情況,資料還能夠復原。

我們再看一些異常情況,因為總共就三個步驟,是以很容易可以枚舉所有可能出現的問題:

我們将最惡心的一種情況排除掉,因為網絡無回報導緻的問題,看看其他問題。

pa ->c b(b機器挂掉): 也就是說,如果在commit b這個步驟失敗,這時候可以很容易的通過直接復原在a的修改,并傳回前端異常,來滿足一緻性問題,但可用性有所喪失,因為這次寫入是失敗的。

在這時的可用性呢? b機器挂掉,對a來說,應該允許送出繼續進行。這樣才能保證服務可用,否則,隻要有任意的一個機器挂掉,整個叢集就不可用,這肯定是不符合預期的嘛。

pa -> c b -> c a(a機器挂掉) :這種情況下,commit a步驟失敗,應該做的事情是,在a這個機器重新恢複後,因為自己的狀态是p a,是以他必須詢問b機器,你送出了沒有啊?如果b機器回答:我送出成功了,那麼a機器也必須将自己的資料也做送出操作,就能達到一緻。

在可用性上面,一台機器挂掉,另外一台還是可以用的,那麼,自然而然的想法是,去另外一台機器上做嘗試。

從上面可以看到,因為b機器已經送出了這條記錄,是以資料已經是最新了,可以基于最新資料做新的送出和其他操作,是安全的。

怎麼樣?覺得繞不繞?不過還沒完呢,我們來看看2pc改的死穴在哪裡。。

還記得剛開始的時候,我們提到了排除掉了一種最惡心的情況,這就是網絡上最臭名昭著的問題,無回報啊無回報。。

無回報這個情況,在2pc改中隻會在一個地方出現,因為隻有一次網絡傳輸過程:

a把自己的狀态設定為prepare,然後傳遞消息給b機器,讓b機器做送出操作,然後b回報a結果。這是唯一的一次網絡調用。

那麼,這無回報意味着什麼呢?

1.b成功送出

2.b 失敗(機器挂掉應該被歸類于此)

3.網絡斷開

更準确的來說,其實從a機器的角度來看這件事,有兩類事情是無法區分出來的:

1)b機器是挂掉了呢?還是隻是網絡斷掉了?

2)要求b做的操作,是成功了呢?還是失敗了呢?

不要小看這兩種情況。。。他意味着兩個悲劇的産生。

首先,一緻性上就出現了問題,無回報的情況下,無法區分成功還是失敗了,于是最安全和保險的方式,就是等着。。。沒錯,你沒看錯,就是死等。等到b給個回報。。。這種在可用性上基本上是0分了。。無論你有多少機器,死等總不是個辦法。。

然後,可用性也出現了個問題,我們來看看這個著名的“腦裂”問題吧:

a得不到b的回報,又為了保證自己的可用性,唯一的選擇就隻好像【p a ->c b(b機器挂掉):】這裡面所提到的方法一樣:等待一段時間,逾時以後,認為b機器挂掉了。于是自己繼續接收新的請求,而不再嘗試同步給b。又因為可用性名額是如此重要,是以這基本成為了在這種情況下的必然選擇,然而,這個選擇會帶來更大的問題,左腦和右腦被分開了!

為什麼?我們假定a所在的機房有一組client,叫做client in a. b 機房有一組client 叫做client in b。開始,a是主機,整個結構worked well.

海量存儲之十六--一緻性和高可用專題

一旦發生斷網

海量存儲之十六--一緻性和高可用專題

在這種情況下,a無法給b傳遞資訊,為了可用性,隻好認為b挂掉了。允許所有client in a 送出請求到自己,不再嘗試同步給b.而b與a的心跳也因為斷網而中斷,他也無法知道,a到底是挂掉了呢?還是隻是網絡斷了,但為了可用性,隻好也把自己設定為主機,允許所有client in b寫入資料。于是。。出現了兩個主機。。。腦裂。

這就是兩段送出問題解決了什麼,以及面臨了什麼困境。

碰到問題,就要去解決,是以,針對一緻性問題上的那個“死等”的萌呆屬性,有人提出了三段送出協定,使用增加的一段送出來減少這種死等的情況。不過3pc基本上沒有人在用,因為有其他協定可以做到更多的特性的同時又解決了死等的問題,是以3pc我們在這裡就不表了。3pc是無法解決腦裂問題的,是以更多的人把3pc當做發展過程中的一顆路旁的小石頭。。

而針對腦裂,最簡單的解決問題的方法,就是引入第三視點,observer。

既然兩個人之間,直接通過網絡無法區分出對方是不是挂掉了,那麼,放另外一台機器在第三個機房,如果真的碰到無響應的時候,就去問問observer:對方活着沒有啊?就可以防止腦裂問題了。但這種方法是無法解決一緻性問題中的死等問題的。。。

是以,最容易想到的方式就是,3pc observer,完美解決雙機一緻性和安全性問題。

後記3317字。nnd我本來以為可以5篇兒紙說完這個問題的。。現在發現剛闡述了很小一部分。。果然一緻性和可用性真不是個簡單的問題。今天到這,這個做個專題吧。

該文章轉載自:淘寶沈詢_whisperxd的部落格

繼續閱讀