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弱一些的一致性模型,要求:
-
進程內,對同一個變量的讀寫保持順序
-
進程間,“看到”的變量的變更順序是一致的(不要求和“物理時間”下的順序保持一致)
以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更嚴格一些:
-
進程內,對同一個變量的讀寫操作保持順序
-
進程間,“看到”的變量的變更順序和全局“物理時鍾”下的順序是一致的
即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是一種弱一致性模型,僅要求有因果關系的操作順序性得到保證,非因果關系的操作順序性沒有要求。
具體如下:
-
本地順序:統一進程中,事件的執行順序即為本地的因果順序
-
異地順序:如果讀操作返回的是寫操作的值,那么該寫操作一定在讀操作之前
-
閉包傳遞:如果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是最終一致,只要求在沒有新寫入的情況下,最終所有數據達成一致,常見於一些異步復制的系統。
最后
螞蟻中間件團隊是服務於整個螞蟻金服集團的核心技術團隊,打造了世界領先的金融級分布式架構的基礎中間件平台。我們是隸屬於螞蟻中間件的通信中間件團隊,致力於打造金融級的分布式消息中間件。
如果你對分布式消息中間件、流計算框架、高可靠存儲系統的設計和研發有興趣,請通過公眾號留下你的信息,我會和你聯系詳聊。