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