ZooKeeper 的作用
ZooKeeper 是一個開源的分布式協(xié)調(diào)服務(wù)框架,你也可以認為它是一個可以保證一致性的分布式(小量)存儲系統(tǒng)。特別適合存儲一些公共的配置信息、集群的一些元數(shù)據(jù)等等。
它有持久節(jié)點和臨時節(jié)點,而臨時節(jié)點這個玩意再配合 Watcher 機制就很有用。
當創(chuàng)建臨時節(jié)點的客戶端與 ZooKeeper 斷連之后,這個臨時節(jié)點就會消失,并且訂閱了節(jié)點狀態(tài)變更的客戶端會收到這個節(jié)點狀態(tài)變更的通知。
所以集群中某一服務(wù)上線或者下線,都可以被檢測到。因此可以用來實現(xiàn)服務(wù)發(fā)現(xiàn),也可以實現(xiàn)故障轉(zhuǎn)移的監(jiān)聽機制。
Kafka 就是強依賴于 ZooKeeper,沒有 ZooKeeper 的話 Kafka 都無法運行。
ZooKeeper 為 Kafka 提供了元數(shù)據(jù)的管理,例如一些 Broker 的信息、主題數(shù)據(jù)、分區(qū)數(shù)據(jù)等等。
在每個 Broker 啟動的時候,都會和 ZooKeeper 進行交互,這樣 ZooKeeper 就存儲了集群中所有的主題、配置、副本等信息。
還有一些選舉、擴容等機制也都依賴 ZooKeeper 。
例如控制器的選舉:每個 Broker 啟動都會嘗試在 ZooKeeper 注冊/controller
臨時節(jié)點來競選控制器,第一個創(chuàng)建/controller
節(jié)點的 Broker 會被指定為控制器。
競爭失敗的節(jié)點也會依賴 watcher 機制,監(jiān)聽這個節(jié)點,如果控制器宕機了,那么其它 Broker 會繼續(xù)來爭搶,實現(xiàn)控制器的 failover。
從上面就可以得知 ZooKeeper 對 Kafka 來說,很重要。
那為什么要拋棄 ZooKeeper
軟件架構(gòu)都是演進的,之所以要變更那肯定是因為出現(xiàn)了瓶頸。
先來看看運維的層面的問題。
首先身為一個中間件,需要依賴另一個中間件,這就感覺有點奇怪。
你要說依賴 Netty 這種,那肯定是沒問題的。
但是 Kafka 的運行需要提供 ZooKeeper 集群,這其實有點怪怪的。
就等于如果你公司要上 Kafka 就得跟著上 ZooKeeper ,被動了增加了運維的復(fù)雜度。
好比你去商場買衣服,要買個上衣,服務(wù)員說不單賣,要買就得買一套,這錢是不是多花了?
所以運維人員不僅得照顧 Kafka 集群,還得照顧 ZooKeeper 集群。
再看性能層面的問題。
ZooKeeper 有個特點,強一致性。
如果 ZooKeeper 集群的某個節(jié)點的數(shù)據(jù)發(fā)生變更,則會通知其它 ZooKeeper 節(jié)點同時執(zhí)行更新,就得等著大家(超過半數(shù))都寫完了才行,這寫入的性能就比較差了。
然后看到上面我說的小量存儲系統(tǒng)了吧,一般而言,ZooKeeper 只適用于存儲一些簡單的配置或者是集群的元數(shù)據(jù),不是真正意義上的存儲系統(tǒng)。
如果寫入的數(shù)據(jù)量過大,ZooKeeper 的性能和穩(wěn)定性就會下降,可能導(dǎo)致 Watch 的延時或丟失。
所以在 Kafka 集群比較大,分區(qū)數(shù)很多的時候,ZooKeeper 存儲的元數(shù)據(jù)就會很多,性能就差了。
還有,ZooKeeper 也是分布式的,也需要選舉,它的選舉也不快,而且發(fā)生選舉的那段時候是不提供服務(wù)的!
基于 ZooKeeper 的性能問題 Kafka 之前就做了一些升級。
例如以前 Consumer 的位移數(shù)據(jù)是保存在 ZooKeeper 上的,所以當提交位移或者獲取位移的時候都需要訪問 ZooKeeper ,這量一大 ZooKeeper 就頂不住。
所以后面引入了位移主題(Topic是__consumer_offsets),將位移的提交和獲取當做消息一樣來處理,存儲在日志中,避免了頻繁訪問 ZooKeeper 性能差的問題。
還有像一些大公司,可能要支持百萬分區(qū)級別,這目前的 Kafka 單集群架構(gòu)下是無法支持穩(wěn)定運行的,也就是目前單集群可以承載的分區(qū)數(shù)有限。
所以 Kafka 需要去 ZooKeeper 。
所以沒了 Zookeeper 之后的Kafka 的怎樣的?
沒了 Zookeeper 的 Kafka 就把元數(shù)據(jù)存儲到自己內(nèi)部了,利用之前的 Log 存儲機制來保存元數(shù)據(jù)。
就和上面說到的位移主題一樣,會有一個元數(shù)據(jù)主題,元數(shù)據(jù)會像普通消息一樣保存在 Log 中。
所以元數(shù)據(jù)和之前的位移一樣,利用現(xiàn)有的消息存儲機制稍加改造來實現(xiàn)了功能,完美!
然后還搞了個 KRaft 來實現(xiàn) Controller Quorum。
圖來自 confluent
這個協(xié)議是基于 Raft 的,協(xié)議具體就不展開了,就理解為它能解決 Controller Leader 的選舉,并且讓所有節(jié)點達成共識。
在之前基于 Zookeeper 實現(xiàn)的單個 Controller 在分區(qū)數(shù)太大的時候還有個問題,故障轉(zhuǎn)移太慢了。
當 Controller 變更的時候,需要重新加載所有的元數(shù)據(jù)到新的 Controller 身上,并且需要把這些元數(shù)據(jù)同步給集群內(nèi)的所有 Broker。
而 Controller Quorum 中的 Leader 選舉切換則很快,因為元數(shù)據(jù)都已經(jīng)在 quorum 中同步了,也就是 quorum 的 Broker 都已經(jīng)有全部了元數(shù)據(jù),所以不需要重新加載元數(shù)據(jù)!
并且其它 Broker 已經(jīng)基于 Log 存儲了一些元數(shù)據(jù),所以只需要增量更新即可,不需要全量了。
這波改造下來就解決了之前元數(shù)據(jù)過多的問題,可以支持更多的分區(qū)!
最后
可能看到這里有人會說,那為何一開始不這么實現(xiàn)?
因為 ZooKeeper 是一個功能強大且經(jīng)過驗證的工具,在早期利用它來實現(xiàn)一些功能,多簡單喲,都不需要自己實現(xiàn)。
要不是 ZooKeeper 的機制導(dǎo)致了這個瓶頸,也不可能會有這個改造的。
軟件就是這樣,沒必要重復(fù)造輪子,合適就好。文章來源:http://www.zghlxwxcb.cn/news/detail-460915.html
參考資料:文章來源地址http://www.zghlxwxcb.cn/news/detail-460915.html
- https://www.confluent.io/blog/kafka-without-zookeeper-a-sneakpeek/
- https://time.geekbang.org/column/article/253202
- https://www.infoq.cn/article/PHF3gFjUTDhWmctg6kXe
到了這里,關(guān)于ZooKeeper 用的好好地,Kafka 為什么要拋棄 ZooKeeper?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!