ZooKeeper真的low嗎?上千節點場景配置服務討論
以下一次關于ZooKeeper為主的一次激烈的技術討論。
為什么說一套系統用了ZooKeeper,這個系統一定很low?
ZooKeeper = low?
提出此觀點的架構師介紹其原因如下。
在Docker環境下,通常虛機會比較多,我們發現ZooKeeper不能承受太多節點。我們的游戲平臺是一個多租戶場景,需要頻繁進行創建及刪除,在這種情況下如果超過3,000虛擬機,ZooKeeper就不行了。
當ZooKeeper掛了后,meta數據也會跟著丟了。Meta數據和和監控功能在ZooKeeper當初設計時并沒有考慮的問題,因此后來我們打算自己造輪子,將這個需求實現。
我也并非說ZooKeeper一無是處,ZooKeeper有它適合使用的場景,比如Hadoop那種場景ZooKeeper就可以工作得很好,但并不是所有場景都適用。Tim說過一句經典的話,Redis是把好錘子,但不能把所有存儲的問題都當做釘子。ZooKeeper也是一樣,不是所有的配置的問題都適合拿它來解決。
其他一些網友的看法。
Z: 同意ZooKeeper是有很多運維的問題,一個解決方法是自己實現一個single node all in memory的lock service,然后運行在多個機器上,用ZooKeeper當作一個distributed lock來選一個master,這樣ZooKeeper上的壓力就小多了,而且不會隨著集群大小增加而增加。
Y: Kafka里使用ZooKeeper的方式有好幾個地方可以借鑒。除了上面說的選一個master處理的方式外,為了避免訂閱大量節點,也可以單設置一個變更節點,然后只訂閱這個變更節點。
G: Kafka集群依賴于ZooKeeper,但ZooKeeper也是Kafka的瓶頸。
某知名大型互聯網公司方案
某知名大型互聯網公司的架構師也基本認可上述觀點,其新開發的服務框架中不再采用ZooKeeper作為注冊中心,主要說明如下
1. 隨著部署規模增大,客戶端增多,ZooKeeper服務器中節點數量大增,核心ZooKeeper集群5臺,每臺服務器1,5000左右的長鏈接,近43萬個節點,平均30余萬watch。每個上線日,ZooKeeper服務器的流量都能上200mb/s,通過mntr的觀察zk_outstanding_requests 經常達到300M以上;
2. 有業務方報告,應用啟動后連上ZooKeeper但一直讀失敗(讀數據返回為null),也就是取服務列表失敗,一段時間如半小時后自動恢復,查看zk server端日志,只看到一堆session過期的警告,沒有其他異常;
3. 由于歷史原因,ZooKeeper服務器與其他應用共用,40萬+節點中60%是我們的,其他應用也是重度依賴zookeeper,互相之間有影響;
4. ZooKeeper推送的頻率、內容,我們自己不能控制,比如一個600 provider,12000 consumer的服務,如果新增一個provider,其實并不是每個consumer都需要通知的,但目前的機制下consumer監聽一個目錄,每個consumer都會得到一次provider列表推送;還有我們想在推送前根據一定的規則對provider列表做動態過濾排序,這個需求在zookeeper服務端也沒法實現。
5. ZooKeeper客戶端使用的是 172.17.xx.yy,172.17.xx.yz:2181 這樣的ip串方式連接,后期想添加服務器分散主集群讀寫壓力,也不好實現,因為需要更改地址串,需要update配置的客戶端太多了;
6. 跨機房容災方面,一旦出現機房間通信問題,另一個機房的部署的Observer節點,就不可讀寫了;
7. provider約6萬實例,consumer22萬實例;
基于以上的原因,新的方案實現也很簡單,自己實現了一個服務用來做注冊中心的,實現的是服務注冊/訂閱方面的功能。它負責接收長鏈接并推送,數據存儲在MySQL。
Q:使用ZooKeeper主要是它實現了強一致性,你這個注冊中心是單點的吧?master election用ZooKeeper?注冊中心會成為新的瓶頸和故障點?
A:性能方面完全夠用,因為這個服務也是集群部署的,客戶端首先訪問一個http接口拿到所有服務器的地址,并優先訪問本機房的注冊中心。注冊中心基本讀多寫少,內存里面也緩存provider列表,不會有太大壓力到MySQL;存儲上通過MySQL實現一致性保證。
Q:跨機房容災方面有什么優化嗎?如果網絡沒有足夠的redundency,一旦出現network partiton,那么有一個機房就沒辦法到quorum了?
A:通過多機房部署,每個機房保證至少2個節點,本機房掛了還可以訪問其它機房,并且在客戶端本地還有緩存文件。
Q:當配置變化,client以http輪詢方式去感知嗎?
A:Session過期那個,開始我們設的是很短,后來發現不對,網絡一閃斷,大量掉節點?,F在我們自己實現的服務,半分鐘一心跳,幾個心跳沒收到我才認為下線了。如果provider列表發生變化,我這邊服務端會主動推送的,因為用的是TCP長連接。
Q: Client有沒有主動發現本地cache與服務端數據不一致的機制?例如當provider列表發生變化且服務端通過TCP長連給client推送失敗的場景。
A:有,我們心跳帶本地版本號的,如果與服務端不一致的話,會觸發服務端再次推送;
另一知名大型互聯網公司ZooKeeper運行現狀
而另外一知名大公司架構師認為如果consumer數量沒有那么多,用ZooKeeper也能較好滿足要求。其業務場景的ZooKeepr使用及運行情況如下。
線上的單個ZooKeeper節點平均連接數是6K,watcher是30萬,netIO不高,ZooKeeper的機器配置比較差,用的是4G 4CPU 的虛擬機,5個節點,最多的consumer不超過200,平均consumer數量就5,6個左右。
目前線上provider數3萬左右實例數,consumer數10萬左右,目前運行的沒什么問題。3萬個,如果每個服務10個實例,也就3,000個服務,全公司的,也沒多少。看起來是多了點。 跟公司發展歷史及使用場景關系很大。
之前關于ZooKeeper踩坑最多的是在客戶端上,最開始用的是netflix的curator(后來貢獻給apache,但是我們用的是老的,沒升級),遇到網絡閃斷重連不上,然后死循環一樣,升級到apache curator就好了。
后來遇到一個問題是,如果注冊watcher太多,發生重連的時候,zk client會自動注冊之前的所有watcher,這樣會導致一個包的大小超過1M,然后也就重連不上又不斷地重連,后來hack了zk client解決了這個問題,這個bug到目前為止zk官方仍然沒有修復。
不過這些坑基本上遇到一個可以解決一個,但是目前有一個問題目前也沒找到好的解決方案,那就是業務方系統load變高,或者發生長時間gc,導致zk重連甚至session過期。
另外關于zk連接,我們在最底下做了連接共享,因為好多服務都依賴zk,這個也降低了不少連接數。



























