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/做服務發現?/
https://medium.com/knerd/eureka-why-you-shouldnt-use-zookeeper-for-service-discovery-4932c5c7e764
推薦閱讀: