Zookeeper並不保證讀取的是最新數據
如果是對zk進行讀取操作,讀取到的數據可能是過期的舊數據,不是最新的數據。
已上圖為例,如果一個zk集群有10000台節點,當進行寫入的時候,如果已經有6K個節點寫入成功,zk就認為本次寫請求成功。但是這時候如果一個客戶端讀取的剛好是另外4K個節點的數據,那么讀取到的就是舊的過期數據。
在zk的官方文檔中對此有解釋,地址在:https://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html
zookeeper一致性的保證:
ZooKeeper是一種高性能,可擴展的服務,雖然讀取速度比寫入快,但是讀取和寫入操作都設計的極為快速,這樣做的原因是在讀取的情況下,ZooKeeper可能會提供較舊的數據,但這是為了ZooKeeper的一致性保證:
- 順序一致性:來自客戶端的更新將按照發送的順序被寫入到zk
- 原子性:更新操作要么成功要么失敗,沒有中間狀態
- 單系統快照:客戶端將看到服務的相同視圖,而不管它連接到的服務器。
- 可靠性:一旦應用更新,數據將被持久化,直到數據被再次更新,對於該保證有兩個推論:1、如果客戶端得到了成功的返回碼,說明寫入成功,數據被持久化,如果出現了通信錯誤,超時等一些故障,客戶端將不知道更新是否已應用。我們采取措施盡量減少失敗,但唯一的保證是只有成功的返回碼。 (這在Paxos中稱為單調性條件。)2、如果客戶端已經讀取到了數據或者寫入成功了數據,都不會因為zk的失敗而導致回滾;
- 及時性:在一段時間后,客戶端將看到最新的系統更新,在此期間客戶端將看到這種變更。
有時開發人員錯誤地假定ZooKeeper實際上沒有做出另一個保證:跨客戶端的強一致性
ZooKeeper並不保證在每個實例中,兩個不同的客戶端將具有相同的ZooKeeper數據的視圖。由於諸如網絡延遲的因素,一個客戶端可以在另一客戶端被通知該改變之前執行更新,考慮兩個客戶端A和B的場景。如果客戶端A將znode / a的值從0設置為1,則告訴客戶端B讀取/ a,則客戶端B可以讀取舊值0,這取決於它連接到的服務器。如果客戶端A和客戶端B讀取相同的值很重要,則客戶端B應該在執行讀取之前從ZooKeeper API方法調用sync()方法。
zk的sync方法的解釋:異步的實現當前進程與leader之間的指定path的數據同步;
CAP理論
在理論計算機科學中,CAP定理(CAP theorem),又被稱作布魯爾定理(Brewer’s theorem),它指出對於一個分布式計算系統來說,不可能同時滿足以下三點:
- 一致性(Consistence) (等同於所有節點訪問同一份最新的數據副本)
- 可用性(Availability)(每次請求都能獲取到非錯的響應——但是不保證獲取的數據為最新數據)
- 分區容錯性(Network partitioning)(以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味着發生了分區的情況,必須就當前操作在C和A之間做出選擇。)
根據定理,分布式系統只能滿足三項中的兩項而不可能滿足全部三項。理解CAP理論的最簡單方式是想象兩個節點分處分區兩側。允許至少一個節點更新狀態會導致數據不一致,即喪失了C性質。如果為了保證數據一致性,將分區一側的節點設置為不可用,那么又喪失了A性質。除非兩個節點可以互相通信,才能既保證C又保證A,這又會導致喪失P性質
對於zookeeper來說,它實現了A可用性、P分區容錯性、C中的寫入強一致性,喪失的是C中的讀取一致性。
有所喪失,才有所獲得,沒有十全十美。