分佈式系統中一個重要的問題就是數據複製,數據複製通常是爲了加強系統的可用性或提升性能。而實現數據複製的一個主要難題就是保持各個副本的一致性。本文首先討論數據複製的場景中一致性模型如此重要的緣由,而後討論一致性模型的含義,最後分析經常使用的一致性模型。數據庫
**數據複製主要的目的有兩個:可用性和性能。**首先數據複製能夠提升系統的可用性。在保持多副本的狀況,有一個副本不可用,系統切換到其餘副本就會恢復。經常使用的 MySQL 主備同步方案就是一個典型的例子。另外一方面,數據複製可以提供系統的性能。當分佈式系統須要在服務器數量和地理區域上進行擴展時,數據複製是一個至關重要的手段。有了多個數據副本,就能將請求分流;在多個區域提供服務時,也能經過就近原則提升客戶端訪問數據的效率。經常使用的 CDN 技術就是一個典型的例子。 可是數據複製是要付出代價的。**數據複製帶來了多副本數據一致性的問題。**一個副本的數據更新以後,其餘副本必需要保持同步,不然數據不一致就可能致使業務出現問題。所以,每次更新數據對全部副本進行修改的時間以及方式決定了複製代價的大小。全局同步與性能其實是矛盾的,而爲了提升性能,每每會採用放寬一致性要求的方法。所以,咱們須要用一致性模型來理解和推理在分佈式系統中數據複製須要考慮的問題和基本假設。緩存
首先咱們要定義一下一致性模型的術語:服務器
下面是一致性模型的定義: 一致性模型本質上是進程與數據存儲的約定:若是進程遵循某些規則,那麼進程對數據的讀寫操做都是可預期的。併發
上面的定義可能比較抽象,咱們用常見的強一致性模型來通俗的解釋一下:**在線性一致性模型中,進程對一個數據項的讀操做,它期待數據存儲返回的是該數據在最後一次寫操做以後的結果。**這在單機系統裏面很容易實現,在 MySQL 中只要使用加鎖讀的方式就能保證讀取到數據在最後一次寫操做以後的結果。但在分佈式系統中,由於沒有全局時鐘,致使要精肯定義哪次寫操做是最後一次寫操做是很是困難的事情,所以產生了一系列的一致性模型。**每種模型都有效限制了在對一個數據項執行讀操做所應該返回的值。**舉個例子:假設記錄值 X 在節點 M 和 N 上都有副本,當客戶端 A 修改了副本 M 上 X 的值,一段時間以後,客戶端 B 從 N 上讀取 X 的值,此時一致性模型會決定客戶端 B 是否可以讀取到 A 寫入的值。分佈式
一致性模型主要能夠分爲兩類:可以保證全部進程對數據的讀寫順序都保持一致的一致性模型稱爲強一致性模型,而不能保證的一致性模型稱爲弱一致性模型。post
線性一致性也叫嚴格一致性(Strict Consistency)或者原子一致性(Atomic Consistency),它的條件是:性能
線性一致性是對一致性要求最高的一致性模型,就現有技術是不可能實現的。由於它要求全部操做都實時同步,在分佈式系統中要作到全局徹底一致時鐘現有技術是作不到的。首先通訊是必然有延遲的,一旦有延遲,時鐘的同步就無法作到一致。固然不排除之後新的技術可以作到,但目前而言線性一致性是沒法實現的。.net
順序一致性是 Lamport(1979)在解決多處理器系統共享存儲器時首次提出來的。參考我以前寫的文章《分佈式系統:Lamport 邏輯時鐘》。它的條件是:排序
首先咱們先來分析一下線性一致性和順序一致性的相同點在哪裏。他們都可以保證全部進程對數據的讀寫順序保持一致。線性一致性的實現很簡單,就按照全局時鐘(能夠簡單理解爲物理時鐘)爲參考系,全部進程都按照全局時鐘的時間戳來區分事件的前後,那麼必然全部進程看到的數據讀寫操做順序必定是同樣的,由於它們的參考系是同樣的。而順序一致性使用的是邏輯時鐘來做爲分佈式系統中的全局時鐘,進而全部進程也有了一個統一的參考系對讀寫操做進行排序,所以全部進程看到的數據讀寫操做順序也是同樣的。進程
那麼線性一致性和順序一致性的區別在哪裏呢?經過上面的分析能夠發現,**順序一致性雖然經過邏輯時鐘保證全部進程保持一致的讀寫操做順序,但這些讀寫操做的順序跟實際上發生的順序並不必定一致。**而線性一致性是嚴格保證跟實際發生的順序一致的。
因果一致性是一種弱化的順序一致性模型,由於它將具備潛在因果關係的事件和沒有因果關係的事件區分開了。那麼什麼是因果關係?若是事件 B 是由事件 A 引發的或者受事件 A 的影響,那麼這兩個事件就具備因果關係。 舉個分佈式數據庫的示例,假設進程 P1 對數據項 x 進行了寫操做,而後進程 P2 先讀取了 x,而後對 y 進行了寫操做,那麼對 x 的讀操做和對 y 的寫操做就具備潛在的因果關係,由於 y 的計算可能依賴於 P2 讀取到 x 的值(也就是 P1 寫的值)。 另外一方面,若是兩個進程同時對兩個不一樣的數據項進行寫操做,那麼這兩個事件就不具有因果關係。無因果關係的操做稱爲併發操做。這裏只是簡單陳述了一下,深刻的分析見我以前寫的文章《分佈式系統:向量時鐘》。 因果一致性的條件包括:
下面咱們來分析一下爲何說因果一致性是一種弱化的順序一致性模型。順序一致性雖然不保證事件發生的順序跟實際發生的保持一致,可是它可以保證全部進程看到的讀寫操做順序是同樣的。而**因果一致性更進一步弱化了順序一致性中對讀寫操做順序的約束,僅保證有因果關係的讀寫操做有序,沒有因果關係的讀寫操做(併發事件)則不作保證。**也就是說若是是無因果關係的數據操做不一樣進程看到的值是有多是不同,而有因果關係的數據操做不一樣進程看到的值保證是同樣的。
最終一致性是更加弱化的一致性模型,因果一致性起碼還保證了有因果關係的數據不一樣進程讀取到的值保證是同樣的,而最終一致性只保證全部副本的數據最終在某個時刻會保持一致。 從某種意義上講,最終一致性保證的數據在某個時刻會最終保持一致就像是在說:「人總有一天會死」同樣。實際上咱們更加關心的是:
因爲最終一致性對數據一致性的要求比較低,在對性能要求高的場景中是常用的一致性模型。
前面咱們討論的一致性模型都是針對數據存儲的多副本之間如何作到一致性,考慮這麼一種場景:在最終一致性的模型中,若是客戶端在數據不一樣步的時間窗口內訪問不一樣的副本的同一個數據,會出現讀取同一個數據卻獲得不一樣的值的狀況。爲了解決這個問題,有人提出了以客戶端爲中心的一致性模型。以客戶端爲中心的一致性爲單一客戶端提供一致性保證,保證該客戶端對數據存儲的訪問的一致性,可是它不爲不一樣客戶端的併發訪問提供任何一致性保證。 舉個例子:客戶端 A 在副本 M 上讀取 x 的最新值爲 1,假設副本 M 掛了,客戶端 A 鏈接到副本 N 上,此時副本 N 上面的 x 值爲舊版本的 0,那麼一致性模型會保證客戶端 A 讀取到的 x 的值爲 1,而不是舊版本的 0。一種可行的方案就是給數據 x 加版本標記,同時客戶端 A 會緩存 x 的值,經過比較版原本識別數據的新舊,保證客戶端不會讀取到舊的值。
以客戶端爲中心的一致性包含了四種子模型:
數據複製致使了一致性的問題,爲了保持副本的一致性可能會嚴重地影響性能,惟一的解決辦法就是放鬆一致性的要求。經過一致性模型咱們能夠理解和推理在分佈式系統中數據複製須要考慮的問題和基本假設,便於結合具體的業務場景作權衡。每種模型都有效地限制了對一個數據項執行度操做應返回的值。一般來講限制越少的模型越容易應用,但一致性的保證就越弱。
《分佈式系統原理與範型》