瞭解一致性模型

What is Consistency

一致性(Consistency)一直是分佈式系統裏一個很重要的話題。

在存儲系統中,爲了避免數據丟失,我們都會對數據進行持久化。

對數據進行持久化可以避免宕機帶來的數據丟失問題,但是不能解決單機永久性故障的問題。存儲系統作爲基礎設施,在單機上持久化是遠遠不夠的,我們需要將數據複製到多臺機器上以提升系統的可用性和可靠性。

一旦數據被複制到多個節點,那麼就產生了一致性的問題。

系統需要定義一組協議來規定用戶讀寫多副本的行爲,這組協議稱之爲一致性模型(Consistency Model)。在分佈式系統領域,談論一致性時通常談論的都是一致性模型。

Consistency Model

不同的一致性模型對系統的行爲和表現有不同的約束。

Strict Consistency

Strict Consistency是最強的一致性模型,要求任何讀取操作都能讀取到最新的值,換句話說,要求任何寫入操作立即同步給所有進程。在分佈式系統中,數據的同步是需要時間的,因此在分佈式系統下無法嚴格實現Strict Consistency。除非讓所有的讀寫操作都只在一個進程的一個線程中執行或者,讀寫操作被鎖保護起來。(根據CAP的原理,這個一致性模型在沒有犧牲可用性的前提下是不能得到滿足的。 性能也是不可接受的:所有的寫操作需要同步到所有節點之後再返回給客戶端。)

Strict Consistency如上圖所示,在時間軸上,一旦有進行寫入了x=1,其他進程立即能讀到x=1的值。

  • 在W(x)1之後,W(x)2之前,所有進程讀取到的x的值一定是1
  • 在W(x)2之後,W(x)3之前,所有進程讀取到的x的值一定是2
  • 在W(x)3之後,所有進程讀取到的x的值一定是3

Sequential Consistency

Sequential Consistency是比Strict Consistency弱一些的一致性模型,要求:

  1. 進程內,對同一個變量的讀寫保持順序
  2. 進程間,“看到”的變量的變更順序是一致的(不要求和“物理時間”下的順序保持一致)

以Consistency Model中的例子舉例,“看到”以下幾種數據的變更順序都是滿足Sequential Consistency的:

  • x=1, x=2, x=3:滿足Strict Consistency,自然滿足Sequential Consistency
  • x=2, x=1, x=3:滿足了P1中同一個變量的變更順序,不同進程“看到”的順序一致
  • x=1, x=3, x=2:同上

(進程間的事件的順序可以參看《Time, Clocks, and the Ordering of Events in a Distributed System》)

Linearizable Consistency

Linearizable Consistency比Sequential Consistency更嚴格一些:

  1. 進程內,對同一個變量的讀寫操作保持順序
  2. 進程間,“看到”的變量的變更順序和全局“物理時鐘”下的順序是一致的

即Linearizable Consistency是Sequential Consistency的特例,除了滿足所有進程讀到的變更順序是相同,還要求這個順序和全局時鐘下的順序是一致的。

和全局時鐘下的順序保持一致容易理解,即事件的順序和它們在客觀的物理時間下發生的時間順序是一致的。但是如果事件是併發發生的,如何滿足這個順序要求:

如上圖,P0的write x=1操作和P1的read x=0/1有重疊的部分,那麼之間的先後關係是怎樣的?

對於併發的情況Linearizable Consistency並不要求他們之間有確定的順序,即認爲P0的write x=1先於P1的read x=0/1或者P1的read x=0/1先於P0的write x=1都是合理的,但是P0~P3進程看到的這兩個操作的順序必須是確定的、一致的。

上圖的例子中,滿足以下情況的序列都是滿足Linearizable Consistency的:

  • w1 r1 r1 r1(P0->P1->P2->P3或P0->P1->P3->P2)
  • r0 w1 r1 r1(P1->P0->P2->P3或P1->P0->P3->P2)
  • r0 r0 w1 r1(P1->P2->P0->P3)

以上三種一致性模型:Strict Consistency、Linearizable Consistency、Sequential Consistency都是強一致模型

Causal Consistency

Causal Consistency是一種弱一致性模型,僅要求有因果關係的操作順序性得到保證,非因果關係的操作順序性沒有要求。

具體如下:

  1. 本地順序:統一進程中,事件的執行順序即爲本地的因果順序
  2. 異地順序:如果讀操作返回的是寫操作的值,那麼該寫操作一定在讀操作之前
  3. 閉包傳遞:如果a->b,b->c,那麼a->c

(Lamport在《Time, Clocks, and the Ordering of Events in a Distributed System》中描述的happen-before關係及其傳遞閉包)

騰訊朋友圈的例子

在infoq分享的騰訊朋友圈的設計中,他們在設計數據一致性的時候,使用了因果一致性這個模型。用於保證對同一條朋友圈的回覆的一致性,比如這樣的情況:

  • A發了朋友圈內容爲梅里雪山的圖片。
  • B針對內容a回覆了評論:“這裏是哪裏?”
  • C針對B的評論進行了回覆:“這裏是梅里雪山”

那麼,這條朋友圈的顯示中,顯然C針對B的評論,應該在B的評論之後,這是一個因果關係,而其他沒有因果關係的數據,可以允許不一致。

微信的做法是:

  • 每個數據中心,都自己生成唯一的、遞增的數據ID,確保能排重。在下圖的示例中,有三個數據中心,數據中心1生成的數據ID模1爲0,數據中心1生成的數據ID模2爲0,數據中心1生成的數據ID模3爲0,這樣保證了三個數據中心的數據ID不會重複全局唯一。
  • 每條評論都比本地看到所有全局ID大,這樣來確保因果關係。

上圖是Causal Consistency在微信朋友圈中的應用。

比Causal Consistency更弱的一致性模型還有Eventual Consistency(最終一致),比如MySQL的異步複製。

Eventual Consistency:存儲系統保證如果沒有新的寫操作,那麼最終,所有的讀操作都能讀到一致的數據,這裏強調對一個數據項的修改最終會收斂。

總結

本文簡單的描述了分佈式系統中一致性問題的由來,並介紹了幾種一致性模型。其中,Strict Consistency要求最爲嚴格,是現實環境中難以滿足的一種一致性模型,除非犧牲可用性。Linearizable Consistency略弱於Strict Consistency,不要求寫入操作立即可見,但是要求寫入操作保持和全局時鐘下的順序一致。Sequential Consistency則更弱一些,不要求寫入操作保持和全局時鐘下的順序一致,但是要求所有進程看到的寫入操作的順序是一致的。Strict Consistency、Linearizable Consistency、Sequential Consistency都被認爲是強一致的模型。

Causal Consistency被認爲是一種若一致模型,它只要求有因果關係的事件之間保持順序,詳細可以參看Lamport在《Time, Clocks, and the Ordering of Events in a Distributed System》中描述的happen-before關係及其傳遞閉包。

Eventual Consistency是最終一致,只要求在沒有新寫入的情況下,最終所有數據達成一致,常見於一些異步複製的系統。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章