楠木軒

Kafka為什麼要拋棄ZooKeeper?

由 圖門耘 發佈於 科技

相信大家最近一定關注到一款重量級消息中間件Kafka發佈了2.8版本,並且正式移除了對Zookeeper的依賴,背後的設計哲學是什麼呢?僅僅只是減少了一個外部依賴嗎?

答案顯然不會這麼簡單,容我慢慢道來。

在解答為什麼之前,我覺得非常有必要先來闡述一下Zookeeper的經典使用場景。

Zookeeper的經典使用場景

Zookeeper是伴隨着大數據、分佈式領域的興起。大數據中的一個非常重要的議題是如何使用眾多廉價的機器來實現可靠存儲。

所謂廉價的機器就是發生故障的概率非常大,但單台的成本也非常低,分佈式領域希望使用多台機器組成一個集羣,將數據存儲在多台機器上(副本),為了方便實現數據一致性,通常需要從一個複製組中挑選一台主節點用户處理數據的讀寫,其他節點從主節點拷貝數據,當主節點宕機,需要自動進行重新選舉,實現高可用。

上述場景中有一個非常重要的功能Leader選舉,如何選舉出一個主節點、並支持主節點宕機後自動觸發重新選舉,實現主從自動切換,實現高可用。

使用Zookeeper提供的臨時順序節點與事件監聽機制,能非常輕鬆的實現Leader選舉。

上面的t1,t2可以理解為一個組織中的多個成員,能提供相同的服務,但為了實現冷備效果(即同一時間只有一個成員對外提供服務,我們稱之為Leader,當Leader宕機或停止服務後,該組織中的其他成名重新競爭Leader,然後繼續對外提供服務)。

正如上圖所示,Zookeeper是以集羣部署的,能有效避免單點故障,並且集羣內部提供了對數據的強一致性。

當成員需要競爭Leader時,藉助Zookeeper的實現套路是向zookeeper中的一個數據節點(示例中為/app/order-service/leader)節點創建兩個子節點,並且是順序的臨時節點。

客户端判斷創建的節點的序號是否為/app/order-service/leader中序號最小的節點,如果是則成為Leader,對外提供服務;

如果序號不是最小的,則向自己前置的註冊節點刪除事件,一旦Leader代表的進程宕機,它與Zookeeper的會話失效後,與之關聯的臨時節點會被刪除,一旦Leader創建的節點被刪除,其後繼節點會得到通知,從而再次觸發選主,選舉出新的Leader,繼續對外提供服務,保質服務的高可用性。

回顧上述場景,藉助Zookeeper能非常輕鬆的實現選主,為應用提高可用帶來簡便性,主要是利用了Zookeeper的幾個特性:

臨時節點

臨時節點是與會話關聯的,一點創建該臨時節點的會話結束,與之會被自動刪除,無需應用方人工刪除。

順序節點

事件機制

藉助與事件機制,Zookeeper能及時通知存活的其他應用節點,重新觸發選舉,使得實現自動主從切換變的非常簡單。

Kafka對Zookeeper的迫切需求

Kafka中存在眾多的Leader選舉,熟悉Kafka的朋友應該知道,一個主題可以擁有多個分區(數據分片),每一個數據分片可以配置多個副本,如何保證一個分區的數據在多個副本之間的一致性成為一個迫切的需求。

Kafka的實現套路就是一個分區的多個副本,從中選舉出一個Leader用來承擔客户端的讀寫請求,從節點從主節點處拷貝內容,Leader節點根據數據在副本中成功寫入情況,進行抉擇來確定是否寫入成功。

Kafka中topic的分區分佈示意圖:

故此處需要進行Leader選舉,而基於Zookeeper能輕鬆實現,從此一拍即合,開啓了一段“蜜月之旅”。

Zookeeper的致命弱點

Zookeeper是集羣部署,只要集羣中超過半數節點存活,即可提供服務,例如一個由3個節點的Zookeeper,允許1個Zookeeper節點宕機,集羣仍然能提供服務;一個由5個節點的Zookeeper,允許2個節點宕機。

但Zookeeper的設計是CP模型,即要保證數據的強一致性,必然在可用性方面做出犧牲。

Zookeeper集羣中也存在所謂的Leader節點和從節點,Leader節點負責寫,Leader與從節點可用接受讀請求,但在Zookeeper內部節點在選舉時整個Zookeeper無法對外提供服務。當然正常情況下選舉會非常快,但在異常情況下就不好説了,例如Zookeeper節點發生full Gc,此時造成的影響將是毀滅性的。

Zookeeper節點如果頻繁發生Full Gc,此時與客户端的會話將超時,由於此時無法響應客户端的心跳請求(Stop World),從而與會話相關聯的臨時節點將被刪除,注意,此時是所有的臨時節點會被刪除,Zookeeper依賴的事件通知機制將失效,整個集羣的選舉服務將失效。

站在高可用性的角度,Kafka集羣的可用性不僅取決於自身,還受到了外部組件的制約,從長久來看,顯然都不是一個優雅的方案。

隨着分佈式領域相關技術的不斷完善,去中心化的思想逐步興起,去Zookeeper的呼聲也越來越高,在這個進程中湧現了一個非常優秀的算法:Raft協議。

Raft協議的兩個重要組成部分:Leader選舉、日誌複製,而日誌複製為多個副本提供數據強一致性提供了強一致性,並且一個顯著的特點是Raft節點是去中心化的架構,不依賴外部的組件,而是作為一個協議簇嵌入到應用中的,即與應用本身是融合為一體的。

再以Kafka Topic的分佈圖舉例,引用Raft協議的示例圖如下:

關於Raft協議,本文並不打算深入進行探討,但為選主提供了另外一種可行方案,而且還無需依賴第三方組件,何樂而不為呢?故最終Kafka在2.8版本中正式廢棄了Zookeeper,擁抱Raft。

4月23日晚8點,歡迎來到CSDN直播間,與資深行業專家雷明老師一起探討機器學習所必須掌握的數學知識。