ZooKeeper 並不適合做註冊中心
- 2019 年 12 月 25 日
- 筆記
zookeeper 的 CP 模型不適合註冊中心
zookeeper 是一個非常優秀的項目,非常成熟,被大量的團隊使用,但對於服務發現來講,zookeeper 真的是一個錯誤的方案。
在 CAP 模型中,zookeeper 是 CP,意味著面對網路分區時,為了保持一致性,他是不可用的。
因為 zookeeper 是一個分散式協調系統,如果使用最終一致性(AP)的話,將是一個糟糕的設計,他的核心演算法是 Zab,所有設計都是為了一致性。
對於協調系統,這是非常正確的,但是對於服務發現,可用性是第一位的,例如發生了短暫的網路分區時,即使拿到的資訊是有瑕疵的、舊的,也好過完全不可用。
zookeeper 為協調服務所做的一致性保障,用在服務發現場景是錯誤的。
註冊中心本質上的功能就是一個查詢函數:
ServiceList = F(service-name)
以 service-name
為查詢參數,得到對應的可用的服務端點列表 endpoints(ip:port)
。
我們假設不同的客戶端得到的服務列表數據是不一致的,看看有什麼後果。

一個 serviceB 部署了 10 個實例,都註冊到了註冊中心。
現在有 2 個服務調用者 service1 和 service2,從註冊中心獲取 serviceB 的服務列表,但取得的數據不一致。
s1 = { ip1,ip2 ... ip9 } s2 = { ip2,ip3 ... ip10 }
這個不一致帶來的影響是什麼?
就是 serviceB 各個實例的流量不均衡。

ip1 和 ip10 的流量是單份的,ip2-ip9 流量是雙份的。
這個不均衡有什麼嚴重影響嗎?並沒有,完全可以接受,而且,又不會一直這樣。
所以,註冊中心使用最終一致性模型(AP)完全可以的。
現在我們看一下 CP 帶來的不可用的影響。

3個機房部署 5 個 ZK 節點。
現在機房3出現網路分區了,形成了孤島。
發生網路分區時,各個區都會開始選舉 leader,那麼節點數少的那個分區將會停止運行,也就是 ZK5 不可用了。
這時,serviceA 就訪問不了機房1和機房2的 serviceB 了,而且連自己所在機房的 serviceB 也訪問不了了。
不能訪問其他機房還可以理解,不能訪問自己機房的服務就理解不了了,本機房內部的網路好好的,不能因為你註冊中心有問題就不能訪問了吧。
因為註冊中心為了保障數據一致性而放棄了可用性,導致同機房服務之間無法調用,這個是接受不了的。
所以,註冊中心的可用性比數據強一致性更加重要,所以註冊中心應該是偏向 AP,而不是 CP。
以上表述的是 zookeeper 的 CP 模型並不適合註冊中心的需求場景。
zookeeper 的性能不適合註冊中心
在大規模服務集群場景中,zookeeper 的性能也是瓶頸。
zookeeper 所有的寫操作都是 leader 處理的,在大規模服務註冊寫請求時,壓力巨大,而且 leader 是單點,無法水平擴展。
還有所有服務於 zookeeper 的長連接也是很重的負擔。
zookeeper 對每一個寫請求,都會寫一個事務日誌,同時會定期將記憶體數據鏡像dump到磁碟,保持數據一致性和持久性。
這個動作會降低性能,而且對於註冊中心來講,是不需要的。
小結
從 CP 模型上來講,zookeeper 並不適合註冊中心高可用的需要。
從性能上來講,zookeeper 也無法滿足註冊中心大規模且頻繁註冊寫的場景。
你可能會問,zookeeper 既然這麼多問題,他咋不改呢?
其實,這並不算是 zookeeper 的問題,是人家本來就不適合做註冊中心,非要用他的話,肯定一堆問題。
zookeeper 的特長是做分散式協調服務,例如 kafka、hbase、flink、hadoop 等大項目都在用 zookeeper,用的挺好的,因為是用對了地方。
例如可以看下:kafka 中 zookeeper 具體是做什麼的?
你有什麼看法,歡迎留言交流。
參考資料:
http://jm.taobao.org/2018/06/13/%E5%81%9A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%EF%BC%9F/
https://medium.com/knerd/eureka-why-you-shouldnt-use-zookeeper-for-service-discovery-4932c5c7e764