etcd 是線性一致性讀,而 zk 倒是順序一致性讀,再加上各類共識、強弱一致的名詞,看的時候總會混淆,這篇文檔就列舉下分佈式系統中的那些"一致性名詞",引用了不少其餘的文章,不過會多出一些例子來幫助理解。html
在談到一致性這個詞時,你會想到CAP理論的 consistency,或者 ACID 中的 consistency,或者 cache一致性協議的 coherence,仍是 Raft/Paxos 中的 consensus?java
一致性這個詞在不一樣的領域具備不一樣的含義,畢竟這個中文詞在英文中對應了不一樣的術語,consistency,coherence,consensus三個單詞統一翻譯爲」一致性」。所以在談一致性以前,有必要對這幾個概念作一個區分,不然很容易讓人迷惑mysql
Coherence 只出如今Cache Coherence 一詞中,稱爲」緩存一致性」,研究多核場景,即怎麼保證多個核上的CPU 緩存數據是一致的,通常是單機維度的,不算分佈式領域,能夠參考這篇文章git
consensus準確的翻譯是共識,即多個提議者達成共識的過程,例如Paxos,Raft 就是共識算法,paxos 是一種共識理論,分佈式系統是他的場景,一致性是他的目標。github
一些常見的誤解:使用了 Raft或者 paxos 的系統都是線性一致的(Linearizability 即強一致),其實否則,共識算法只能提供基礎,要實現線性一致還須要在算法之上作出更多的努力。redis
由於分佈式系統引入了多個節點,節點規模越大,宕機、網絡時延、網絡分區就會成爲常態,任何一個問題均可能致使節點之間的數據不一致,所以Paxos 和 Raft 準確來說是用來解決一致性問題的共識算法,用於分佈式場景,而非」緩存一致性「這種單機場景。因此不少文章也就簡稱」Paxos是分佈式系統中的一致性算法「,算法
一致性(Consistency)的含義比共識(consensus)要寬泛,一致性指的是多個副本對外呈現的狀態。包括順序一致性、線性一致性、最終一致性等。而共識特指達成一致的過程,但注意,共識並不意味着實現了一致性,一些狀況下他是作不到的。sql
這裏提一下Paxos,Paxos 實際上是一類協議,Paxos 中包含 Basic Paxos、Multi-Paxos、Cheap Paxos 和其餘的變種。Raft 就是 Multi-Paxos 的一個變種,Raft 經過簡化 Multi-Paxos 的模型,實現了一種更容易讓人理解和工程實現的共識算法,數據庫
Paxos是第一個被證實完備的共識算法,可以讓分佈式網絡中的節點在出現錯誤時仍然保持一致,固然前提是沒有惡意節點,也就是拜占庭將軍問題。在傳統的分佈式系統領域是不須要擔憂這種問題的,由於不管是分佈式數據庫、消息隊列、分佈式存儲,你的機器都不會故意發送錯誤信息,最多見的問題反而是節點失去響應,因此它們在這種前提下,Paxos是足夠用的。apache
consensus共識在實現機制上屬於複製狀態機(Replicated State Machine)的範疇,複製狀態機是一種頗有效的容錯技術,基於複製日誌來實現,每一個 Server 存儲着一份包含命令序列的日誌文件,狀態機會按順序執行這些命令。由於日誌中的命令和順序都相同,所以全部節點會獲得相同的數據。
所以保證系統一致性就簡化爲保證操做日誌的一致,這種複製日誌的方式被大量運用,如 GSF、HDFS、ZooKeeper和 etcd 都是這種機制。
共識算法還有一個很重要的領域,就是比較火的區塊鏈,好比工做量證實(POW)、權益證實(POS)和委託權益證實(DPOS)、置信度證實(PoB)等等,都是共識算法,這篇文章就列出來了 30 種
你們熟知的zk、etcd這種之因此叫「傳統分佈式」,就是相對於區塊鏈這種」新型分佈式系統「而言的,都是多節點共同工做,只是區塊鏈有幾點特殊:
介紹完了Coherence和consensus共識,咱們來看consistency一致性,也就是咱們平時說的最多的 CAP、Base、ACID之類。
最簡單的,客戶端C1將系統中的一個值K由V1更新爲V2,客戶端C2/C3/C4..須要當即讀取到K的最新值
一致性要求的是一致,並非正確,若是全部節點一致給出一個」錯誤「的答案,那也叫一致性
對於不一樣的場景,用戶角度對於一致性的要求是不同的,例如:
上面是誇張了的用戶狀況,在實際業務中,一致性也是分等級的,如強一致性和弱一致性,怎麼使用要看具體狀況和系統的容忍度。
強一致性和弱一致性只是一種統稱,按照從強到弱,能夠劃分爲
強一致性包括線性一致性和順序一致性,其餘的如最終一致都是弱一致性。
關於強和弱的定義,能夠參考劍橋大學的slide
Strong consistency – ensures that only consistent state can be seen. * All replicas return the same value when queried for the attribute of an object * All replicas return the same value when queried for the attribute of an object. This may be achieved at a cost – high latency. Weak consistency – for when the 「fast access」 requirement dominates. * update some replica, e.g. the closest or some designated replica * the updated replica sends up date messages to all other replicas. * different replicas can return different values for the queried attribute of the object the value should be returned, or 「not known」, with a timestamp * in the long term all updates must propagate to all replicas …….
強一致性集羣中,對任何一個節點發起請求都會獲得相同的回覆,但將產生相對高的延遲。而弱一致性具備更低的響應延遲,但可能會回覆過時的數據,最終一致性便是通過一段時間後終會到達一致的弱一致性。
如買最後一張車票,兩個售票處分別經過某種方式確認過這張票的存在。這時,兩家售票處幾乎同時分別來了一個乘客要買這張票,從各自「觀察」看來,本身一方的乘客都是先到的,這種狀況下,怎麼能達成對結果的共識呢?看起來很容易,賣給物理時間上率先提交請求的乘客便可。
然而,對於兩個來自不一樣位置的請求來講,要判斷在時間上的「前後」關係並非那麼容易。兩個車站的時鐘時刻多是不一致的,時鐘計時可能不精確的,根據相對論的觀點,不一樣空間位置的時間是不一致的。所以追求絕對時間戳的方案是不可行的,能作的是要對事件的發生進行排序。
這也是解決分佈式系統領域不少問題的核心祕訣:把不一樣時空發生的多個事件進行全局惟一排序,並且這個順序還得是你們都承認的,排了序,一個一個處理就好了,和單機沒有任何區別(不考慮忽然故障狀況,只考慮共識機制)
若是存在可靠的物理時鐘,實現排序每每更爲簡單。高精度的石英鐘的漂移率爲 10的-7 次方,最準確的原子震盪時鐘的漂移率爲 10的-13 次方。Google 曾在其分佈式數據庫 Spanner 中採用基於原子時鐘和 GPS 的「TrueTime」方案,可以將不一樣數據中心的時間誤差控制在 10ms 置信區間。在不考慮成本的前提下,這種方案簡單、有效。然而,計算機系統的時鐘偏差要大得多,這就形成分佈式系統達成一致順序十分具備挑戰,或者說基本不可能。
要實現絕對理想的嚴格一致性(Strict Consistency)代價很大。除非系統不發生任何故障,並且全部節點之間的通訊無需任什麼時候間,此時整個系統其實就等價於一臺機器了。所以根據實際需求的不用,人們可能選擇不一樣強度的一致性。
雖然強度上 線性一致性 > 順序一致性,但由於順序一致性出現的時間比較早(1979年),線性是在順序的基礎上的增強(1990 年)。所以先介紹下 順序一致性
順序一致性也算強一致性的一種,他的原理比較晦澀,論文看這裏
舉例說明1:下面的圖知足了順序一致,但不知足線性一致。
從圖上看,進程P1,P2的一致性並無衝突。由於從這兩個進程的角度來看,順序應該是這樣的:
Write(y,2), Read(x,0), Write(x,4), Read(y,2)
這個順序對於兩個進程內部的讀寫順序都是合理的,只是這個順序與全局時鐘下看到的順序並不同。在全局時鐘的觀點來看,P2進程對變量X的讀操做在P1進程對變量X的寫操做以後,然而P2讀出來的倒是舊的數據0
舉例說明 2:
假設咱們有個分佈式 KV 系統,如下是四個進程 對其的操做順序和結果:
--表示持續的時間,由於一次寫入或者讀取,客戶端從發起到響應是有時間的,發起早的客戶端,不必定拿到數據就早,有可能由於網絡延遲反而會更晚。
狀況 1:
A: --W(x,1)---------------------- B: --W(x,2)---------------------- C: -R(x,1)- --R(x,2)- D: -R(x,1)- --R(x,2)--
狀況 2:
A: --W(x,1)---------------------- B: --W(x,2)---------------------- C: -R(x,2)- --R(x,1)- D: -R(x,2)- --R(x,1)--
上面狀況 1 和 2 都是知足順序一致性的,C 和 D 拿的順序都是 1-2,或 2-1,只要CD 的順序一致,就是知足順序一致性。只是從全局看來,狀況 1 更真實,狀況 2 就顯得」錯誤「了,由於狀況2 是這樣的順序
B W(x,2) -> A W(x,1) -> C R(x,2) -> D R(x,2) -> C R(x,1) -> D R(x,1)
不過一致性不保證正確性,因此這仍然是一個順序一致。再加一種狀況 3:
狀況 3:
A: --W(x,1)---------------------- B: --W(x,2)---------------------- C: -R(x,2)- --R(x,1)- D: -R(x,1)- --R(x,2)--
狀況 3 就不屬於順序一致了,由於C 和 D 兩個進程的讀取順序不一樣了。
回到狀況 2,C 和 D 拿數據發起的時間是不一樣的,且有重疊,有可能 C 拿到 1 的時候,D 已經拿到了 2,這就致使了不一樣的客戶端在相同的時間獲取了不同的數據,但其實這種模式在現實中的用的挺普遍的:
如:你在Twitter上寫了2條推文,你的操做會耗費必定的時間滲透進一層層的緩存系統,不一樣的朋友將在不一樣的時間看到你的信息,但每一個朋友都會以相同順序看到了你的2條推文,不會是亂序。只是一個朋友已經看到了第二條,一個朋友纔剛看到第一條,不過不要緊,他總會看到兩條,順序沒錯就行,無傷大雅。
但有些時候,順序一致是不知足要求的,舉例說明 3:
從時間軸上能夠看到,B0 發生在 A0 以前,讀取到的 x 值爲0。B2 發生在 A0 以後,讀取到的 x 值爲1。而讀操做 B1,C0,C1 與寫操做 A0 在時間軸上有重疊,所以他們可能讀取到舊的值0,也可能讀取到新的值1。注意,C1 發生在 B1 以後(兩者在時間軸上沒有重疊),可是 B1 看到 x 的新值,C1 反而看到的是舊值。即對用戶來講,x 的值發生了回跳。
即要求任何一次讀都能讀到最新數據,和全局時鐘一致。對比例1,既知足順序一致又知足線性一一致應該是這樣的:
![](http://vermouth-blog-image.os...
)
每一個讀操做都讀到了該變量的最新寫的結果,同時兩個進程看到的操做順序與全局時鐘的順序同樣,都是Write(y,2), Read(x,4), Write(x,4), Read(y,2)
一種說法是 ZooKeeper 是最終一致性,由於因爲多副本、以及保證大多數成功的 Zab 協議,當一個客戶端進程寫入一個新值,另一個客戶端進程不能保證立刻就能讀到這個值,可是能保證最終能讀取到這個值。
另一種說法是 ZooKeeper 的 Zab 協議相似於 Paxos 協議,提供了強一致性。
但這兩種說法都不許確,ZooKeeper 文檔中明確寫明它的一致性是 Sequential consistency即順序一致。
ZooKeeper中針對同一個Follower A提交的寫請求request一、request2,某些Follower雖然可能不能在請求提交成功後當即看到(也就是強一致性),但通過自身與Leader之間的同步後,這些Follower在看到這兩個請求時,必定是先看到request1,而後再看到request2,兩個請求之間不會亂序,即順序一致性
其實,實現上ZooKeeper 的一致性更復雜一些,ZooKeeper 的讀操做是 sequential consistency 的,ZooKeeper 的寫操做是 linearizability 的,關於這個說法,ZooKeeper 的官方文檔中沒有寫出來,可是在社區的郵件組有詳細的討論。ZooKeeper 的論文《Modular Composition of Coordination Services》 中也有提到這個觀點。
總結一下,能夠這麼理解 ZooKeeper:從總體(read 操做 +write 操做)上來講是 sequential consistency,寫操做實現了 Linearizability。
線性一致性又被稱爲強一致性、嚴格一致性、原子一致性。是程序能實現的最高的一致性模型,也是分佈式系統用戶最指望的一致性。CAP 中的 C 通常就指它
順序一致性中進程只關心你們認同的順序同樣就行,不須要與全局時鐘一致,線性就更嚴格,從這種偏序(partial order)要達到全序(total order)
要求是:
以上面的例 3 繼續討論:
B1 看到 x 的新值,C1 反而看到的是舊值。即對用戶來講,x 的值發生了回跳。
在線性一致的系統中,若是 B1 看到的 x 值爲1,則 C1 看到的值也必定爲1。任何操做在該系統生效的時刻都對應時間軸上的一個點。若是咱們把這些時刻鏈接起來,以下圖中紫線所示,則這條線會一直沿時間軸向前,不會反向回跳。因此任何操做都須要互相比較決定,誰發生在前,誰發生在後。例如 B1 發生在 A0 前,C1 發生在 A0 後。而在前面順序一致性模型中,咱們沒法比較諸如 B1 和 A0 的前後關係。
線性一致性的理論在軟件有哪些體現呢?
上面提到ZooKeeper的寫是線性一致性,讀是順序一致性。而 etcd讀寫都作了線性一致,即 etcd 是標準的強一致性保證。
etcd是基於raft來實現的,raft是共識算法,雖然共識和一致性的關係很微妙,常常一塊兒討論,但共識算法只是提供基礎,要實現線性一致還須要在算法之上作出更多的努力如庫封裝,代碼實現等。如raft中對於一致性讀給出了兩種方案,來保證處理此次讀請求的必定是 Leader:
基於 raft 的軟件有不少,如 etcd、tidb、SOFAJRaft等,這些軟件在實現一致讀時都是基於這兩種方式。
關於 etcd 的選主架構這裏不作描述,能夠看這篇文章,這裏對ReadIndex和Lease Read作下解釋,即etcd 中線性一致性讀的具體實現
因爲在 Raft 算法中,寫操做成功僅僅意味着日誌達成了一致(已經落盤),而並不能確保當前狀態機也已經 apply 了日誌。狀態機 apply 日誌的行爲在大多數 Raft 算法的實現中都是異步的,因此此時讀取狀態機並不能準確反應數據的狀態,極可能會讀到過時數據。
基於以上這個緣由,要想實現線性一致性讀,一個較爲簡單通用的策略就是:每次讀操做的時候記錄此時集羣的 commited index,當狀態機的 apply index 大於或等於 commited index 時纔讀取數據並返回。因爲此時狀態機已經把讀請求發起時的已提交日誌進行了 apply 動做,因此此時狀態機的狀態就能夠反應讀請求發起時的狀態,符合線性一致性讀的要求。這即是 ReadIndex 算法。
那如何準確獲取集羣的 commited index ?若是獲取到的 committed index 不許確,那麼以不許確的 committed index 爲基準的 ReadIndex 算法將可能拿到過時數據。
爲了確保 committed index 的準確,咱們須要:
leader 會發起一次廣播請求,若是還能收到大多數節點的應答,則說明此時 leader 仍是 leader。這點很是關鍵,若是沒有這個環節,leader 有可能因網絡分區等緣由已再也不是 leader,若是讀請求依然由過時的 leader 處理,那麼就將有可能讀到過去的數據。
這樣,咱們從 leader 獲取到的 commited index 就做爲這次讀請求的 ReadIndex。
以網絡分區爲例:
如上圖所示:
這樣一來,Raft 算法就能夠保障 CAP 中的 C 和 P,但沒法保障 A:網絡分區時並非全部節點均可響應請求,少數節點的分區將沒法進行服務,從而不符合 Availability。所以,Raft 算法是 CP 類型的一致性算法。
Raft保證讀請求Linearizability的方法:
Serializability是數據庫領域的概念,而Linearizability是分佈式系統、併發編程領域的東西,在這個分佈式SQL時代,天然Linearizability和Serializability會常常一塊兒出現。
Serializable的含義是:對併發事務包含的操做進行調度後的結果和某種把這些事務一個接一個的執行以後的結果同樣。最簡單的一種調度實現就是真的把全部的事務進行排隊,一個個的執行,顯然這知足Serializability,問題就是性能。能夠看出Serializability是與數據庫事務相關的一個概念,一個事務包含多個讀,寫操做,這些操做由涉及到多個數據對象。
舉個最簡單的例子:兩個事務T1,T2,T1先開始,更新數據對象o,T1提交。接着T2開始,讀數據對象o,提交。如下兩種調度:
因果一致性,屬於弱一致性,由於在Causal consistency中,只對有因果關係的事件有順序要求。
沒有因果一致性時會發生以下情形:
因此不少系統採用因果一致性系統來避免這種問題,例如微信的朋友圈就採用了因果一致性,能夠參考:https://www.useit.com.cn/thre...
最終一致性這個詞你們聽到的次數應該是最多的,也是弱一致性,不過由於大多數場景下用戶能夠接受,應用也就比較普遍。
理念:不保證在任意時刻任意節點上的同一份數據都是相同的,可是隨着時間的遷移,不一樣節點上的同一份數據老是在向趨同的方向變化。
簡單說,就是在一段時間後,節點間的數據會最終達到一致狀態。不過最終一致性的要求很是低,除了像gossip這樣明確以最終一致性爲賣點的協議外,包括redis主備、mongoDB、乃至mysql熱備均可以算是最終一致性,甚至若是我記錄操做日誌,而後在副本故障了100天以後手動在副本上執行日誌以達成一致,也算是符合最終一致性的定義。有人說最終一致性就是沒有一致性,由於沒人能夠知道何時算是最終。
上邊提到的因果一致性能夠理解爲是最終一致性的變種, 若是進程 A 通知進程 B 它已經更新了一個數據項,那麼進程 B 的後續訪問將返回更新後的值,而且寫操做將被保證取代前一次寫入。和進程 A 沒有因果關係的 C 的訪問將遵循正常的最終一致性規則。
最終一致其實分支不少,如下都是他的變種:
後面要提到的 BASE理論中的 E,就是Eventual consistency最終一致
ACID 是處理事務的原則,通常特指數據庫的一致性約束,ACID 一致性徹底與數據庫規則相關,包括約束,級聯,觸發器等。在事務開始以前和事務結束之後,都必須遵照這些不變量,保證數據庫的完整性不被破壞,所以 ACID 中的 C 表示數據庫執行事務先後狀態的一致性,防止非法事務致使數據庫被破壞。好比銀行系統 A 和 B 兩個帳戶的餘額總和爲 100,那麼不管 A, B 之間怎麼轉換,這個餘額和是不變,先後一致的。
這裏的C表明的一致性:事務必須遵循數據庫的已定義規則和約束,例如約束,級聯和觸發器。所以,任何寫入數據庫的數據都必須有效,而且完成的任何事務都會改變數據庫的狀態。沒有事務能夠建立無效的數據狀態。注意,這與CAP定理中定義的「一致性」是不一樣的。
ACID 能夠翻譯爲酸,相對應的是鹼,也就是 BASE,不過提BASE以前要先說下 CAP,畢竟 BASE是基於 CAP 提出的折中理論
CAP 理論中的 C 也就是咱們常說的分佈式系統中的一致性,更確切地說,指的是分佈式一致性中的一種: 也就是前面講的線性一致性(Linearizability),也叫作原子一致性(Atomic consistency)。
CAP 理論也是個被濫用的詞彙,關於 CAP 的正肯定義可參考cap faq。不少時候咱們會用 CAP 模型去評估一個分佈式系統,但這篇文章會告訴你 CAP 理論的侷限性,由於按照 CAP 理論,不少系統包括 MongoDB,ZooKeeper 既不知足一致性(線性一致性),也不知足可用性(任意一個工做中的節點都要能夠處理請求),但這並不意味着它們不是優秀的系統,而是 CAP 定理自己的侷限性(沒有考慮處理延遲,容錯等)。
正由於 CAP 中的一致性和可用性是強一致性和高可用,後來又有人基於 CAP 理論 提出了BASE 理論,即基本可用(Basically Available)、軟狀態(Soft State)、最終一致性(Eventual Consistency)。BASE的核心思想是即便沒法作到強一致性,但每一個應用均可以根據自身的業務特色,採用適當的方法來使系統達到最終一致性。顯然,最終一致性弱於 CAP 中的 線性一致性。不少分佈式系統都是基於 BASE 中的」基本可用」和」最終一致性」來實現的,好比 MySQL/PostgreSQL Replication 異步複製。
ACID一致性是有關數據庫規則,若是數據表結構定義一個字段值是惟一的,那麼一致性系統將解決全部操做中致使這個字段值非惟一性的狀況,若是帶有一個外鍵的一行記錄被刪除,那麼其外鍵相關記錄也應該被刪除,這就是ACID一致性的意思。
CAP理論的一致性是保證一樣一個數據在全部不一樣服務器上的拷貝都是相同的,這是一種邏輯保證,而不是物理,由於光速限制,在不一樣服務器上這種複製是須要時間的,集羣經過阻止客戶端查看不一樣節點上還未同步的數據維持邏輯視圖。
當跨分佈式系統提供ACID時,這兩個概念會混淆在一塊兒,Google’s Spanner system可以提供分佈式系統的ACID,其包含ACID+CAP設計,也就是兩階段提交 2PC+ 多副本同步機制(如 Paxos)
ACID 是處理事務的原則,限定了原子性、一致性、隔離性、持久性。ACID、CAP、BASE這些都只是理論,只是在實現時的目標或者折中,ACID 專一於分佈式事務,CAP 和 BASE是分佈式通用理論。
解決分佈式事務時有 2pc、3pc、tcc 等方式,經過增長協調者來進行協商,裏面也有最終一致的思想。
而Paxos協議與分佈式事務並非同一層面的東西,Paxos用於解決多個副本之間的一致性問題。好比日誌同步,保證各個節點的日誌一致性,選主的惟一性。簡而言之,2PC用於保證多個數據分片上事務的原子性,Paxos協議用於保證同一個數據分片在多個副本的一致性,因此二者能夠是互補的關係,不是替代關係。對於2PC協調者單點問題,能夠利用Paxos協議解決,當協調者出問題時,選一個新的協調者繼續提供服務。原理上Paxos和 2PC類似,但目的上是不一樣的。etcd 中也有事務的操做,好比迷你事務
關於 raft 的內容也能夠看下MIT-6.824