Zookeeper能保證任何時刻讀到的數據絕對一致嗎?
Zookeeper的特點就是,分布式,高可用,自帶容錯,所有節點讀到的數據都是一致的。使用的場景通常是微服務的注冊中心,或者一些分布式的開源軟件用來保存元數據,或者監測生命狀態。
這些使用場景默認Zookeeper永遠是可用的,而且去Zookeeper集群旗下的每家分號,獲取的數據都是一樣的,通常情況下也確實如此。
也就是說可用性和一致性是Zookeeper的關鍵特性,作為一個消息的中間商,做了一個可靠的信息傳遞和存儲的角色。
但是了解下Zookeeper的ZAB協議,特別是寫入部分和讀部分,發現了一點細節,Zookeeper不能保證永遠讀到最新的數據,這里簡述下Zookeeper讀寫過程、
寫過程
Leader接收Client的寫請求,廣播給其他Follower節點,其他節點將消息加入待寫隊列,向Leader發送成功消息,過半的Follower同意后,Leader向所有節點發送提交消息,Follower會落實寫請求
讀過程
Client直接訪問一台 Zookeeper獲取信息
也就是說,如果在寫的過程中,過半的follower同意了,這條消息通過寫入,但有一台Zookeeper和Leader無法通信了,或者因為磁盤,內存等原因拒絕寫入了。此時一個client來這個zookeeper節點取數據,那么取的和最新版本的就不一致。
Zookeeper保證了怎樣的一致性
有些地方會寫Zookeeper不保證強一致性,保證了最終一致性。
只是從字面來看,最終一致性聽上去也沒錯,但是從細節來看,還是不准確或者說不對。
首先,CAP中,Zookeeper保證的是CP還是AP。
隨便搜一個科普CAP理論和Zookeeper關系的文章
Zookeeper和CAP理論及一致性原則
可以知道,Zookeeper保證的是CP,即一致性(Consistency)和分區容錯性(Partition-Tolerance)。
而犧牲了部分可用性(Available),
在強一致性的條件下,必須先暫停服務,達成一致性再提供服務,這個同步過程中,請求得不到回應,降低了可用性。
而Zookeeper作為協調服務,需要在大部分情況下都可用,不能出現太明顯的不可用,因此明顯不可用的時段只有Leader選舉階段,此時無法寫入,
Zookeeper選舉機制本身是一種快速選舉的機制,觸發選舉的時候有崩潰恢復和啟動選舉 兩種情況,所以這個問題也可以控制。
從上文簡述的寫入機制來看,Zookeeper是通過Leader來讓各節點的寫入達到一致性。
而達成的一致性,但是這個過程中為了快速響應客戶端,只要follower過半回應即可。
下面說一下幾種一致性的概念
強一致性:又稱線性一致性(linearizability ),
- 1.任意時刻,所有節點中的數據是一樣的,
- 2.一個集群需要對外部提供強一致性,所以只要集群內部某一台服務器的數據發生了改變,那么就需要等待集群內其他服務器的數據同步完成后,才能正常的對外提供服務
- 3.保證了強一致性,務必會損耗可用性
弱一致性:
- 1.系統中的某個數據被更新后,后續對該數據的讀取操作可能得到更新后的值,也可能是更改前的值。
- 2.即使過了不一致時間窗口,后續的讀取也不一定能保證一致。
最終一致性:
- 1.弱一致性的特殊形式,不保證在任意時刻任意節點上的同一份數據都是相同的,但是隨着時間的遷移,不同節點上的同一份數據總是在向趨同的方向變化
- 2.存儲系統保證在沒有新的更新的條件下,最終所有的訪問都是最后更新的值
順序一致性:
- 1.任何一次讀都能讀到某個數據的最近一次寫的數據。
- 2.系統的所有進程的順序一致,而且是合理的。即不需要和全局時鍾下的順序一致,錯的話一起錯,對的話一起對(目前網上能查到的原話)
前三種應該都好理解。強一致性就是在任意時刻,所有節點中的數據都是一樣的。
弱一致性就是可能訪問的到更新后的值,也可能訪問不到。
最終一致性,不保證任何節點都是相同的,也就是說各節點的數據版本可能完全是混亂的,a節點是1,b節點是2,c節點是3,然后a節點更新到2,b節點更新到3,但能保證在沒有更新后達成一致。
順序一致性第一句比較好理解,第二句就比較抽象了,字看的懂,但還是不知道具體說啥,經過查閱資料
Write(x, 4):寫入x=4
Read(x, 0):讀出x=0
1)圖a是滿足順序一致性,但是不滿足強一致性的。原因在於,從全局時鍾的觀點來看,P2進程對變量X的讀操作在P1進程對變量X的寫操作之后,然而讀出來的卻是舊的數據。但是這個圖卻是滿足順序一致性的,因為兩個進程P1,P2的一致性並沒有沖突。從這兩個進程的角度來看,順序應該是這樣的:Write(y,2) , Read(x,0) , Write(x,4), Read(y,2),每個進程內部的讀寫順序都是合理的,但是這個順序與全局時鍾下看到的順序並不一樣。
2)圖b滿足強一致性,因為每個讀操作都讀到了該變量的最新寫的結果,同時兩個進程看到的操作順序與全局時鍾的順序一樣,都是Write(y,2) , Read(x,4) , Write(x,4), Read(y,2)。
3)圖c不滿足順序一致性,當然也就不滿足強一致性了。因為從進程P1的角度看,它對變量Y的讀操作返回了結果0。那么就是說,P1進程的對變量Y的讀操作在P2進程對變量Y的寫操作之前,這意味着它認為的順序是這樣的:write(x,4) , Read(y,0) , Write(y,2), Read(x,0),顯然這個順序又是不能被滿足的,因為最后一個對變量x的讀操作讀出來也是舊的數據。因此這個順序是有沖突的,不滿足順序一致性。
順序一致性內存模型是一個被計算機科學家理想化了的理論參考模型,它為程序員提供了極強的內存可見性保證。順序一致性內存模型有兩大特性:
一個線程中的所有操作必須按照程序的順序來執行。
(不管程序是否同步)所有線程都只能看到一個單一的操作執行順序。在順序一致性內存模型中,每個操作都必須原子執行且立刻對所有線程可見。
這里的順序一致性,講的是一種多線程並發執行下理想情況,包含兩種要求
1.線程中的操作必須按照程序的順序執行,也就是說,不能自己自作主張,更換執行順序
2.線程中的操作是原子性的,執行了就是執行了,沒執行就是沒執行,不存在中間狀態,而且一旦執行,其他變量應該立刻可見。
聯系到zookeeper,說點結論
1.各節點的數據更新必須按照順序進行。
2.數據寫入執行情況,數據版本應對其他節點可見(leader能知道寫入是否成功)。
結合以上,你會發現,zookeeper並不是最終一致性,而是順序一致性。
1.最終一致性的特點是,無法保證任意節點在同一時間某份數據是相同的,但是最終在沒有新的更新時會達成一致。
而Zookeeper所有節點的數據版本都是遞增的,可能會有某個節點因故障版本低於大多數,但是是有序的,不會出現各自增長的情況。
比如,Zookeeper節點可能會出現4台數據是version 5,一台數據是version4。但是不會是5台機器各自更新。
所以這里對順序一致性的定義是
1.任何一次讀都能讀到某個數據的最近一次寫的數據。
2.對其他節點之前的修改是可見(已同步)且確定的,並且新的寫入建立在已經達成同步的基礎上。
結論:Zookeeper寫入是強一致性,讀取是順序一致性。
參考博客:
https://blog.csdn.net/weixin_47727457/article/details/106439452
https://blog.csdn.net/chao2016/article/details/81149674
https://www.cnblogs.com/mkl34367803/p/10704517.html