Kafka基本原理(六)——Zookeeper與Controller

Kafka依賴ZooKeeper,使用ZooKeeper保存集羣中broker、主題、分區的元數據信息和消費者信息,隨着版本的更新(0.9.0.0),這種依賴性正在逐步減輕。老版本的Kafka,消費者的羣組信息、主題信息、消費分區的偏移量等等也是存儲在ZooKeeper,新版本Controller的加入允許broker直接維護這些信息,減少了broker和Zookeeper的聯繫,提高了系統的健壯性。kafka中的Zookeeper、Controller之間聯繫緊密,本文做簡單介紹。

1.ZooKeeper在Kafka中的作用

Kafka利用ZK保存相應的元數據信息,包括:broker信息,Kafka集羣信息,舊版消費者信息以及消費偏移量信息,主題信息,分區狀態信息,分區副本分片方案信息,動態配置信息,等等。

 

Kafka在zk中註冊節點說明:

  • /consumers: 舊版消費者啓動後會在ZK的該節點下創建一個消費者的節點
  • /brokers/seqid: 輔助生成的brokerId,當用戶沒有配置broker.id時,ZK會自動生成一個全局唯一的id。
  • /brokers/topics: 每創建一個主題就會在該目錄下創建一個與該主題同名的節點。
  • /borkers/ids: 當Kafka每啓動一個KafkaServer時就會在該目錄下創建一個名爲{broker.id}的子節點
  • /config/topics: 存儲動態修改主題級別的配置信息
  • /config/clients: 存儲動態修改客戶端級別的配置信息
  • /config/changes: 動態修改配置時存儲相應的信息
  • /admin/delete_topics: 在對主題進行刪除操作時保存待刪除主題的信息
  • /cluster/id: 保存集羣id信息
  • /controller: 保存控制器對應的brokerId信息等
  • /isr_change_notification: 保存Kafka副本ISR列表發生變化時通知的相應路徑

 在zookeeper中存儲的信息有broker,consumer等重要znode信息,每個kafka節點會在zookeeper中註冊該機器的配置信息,註冊完的kafka節點的topic信息會存在topics目錄下面。


在Kafka的早期版本中,並沒有採用Kafka Controller這樣一個概念來對分區和副本的狀態進行管理,而是依賴於Zookeeper,每個broker都會在Zookeeper上爲分區和副本註冊大量的監聽器(Watcher)。當分區或者副本狀態變化時,會喚醒很多不必要的監聽器,這種嚴重依賴於Zookeeper的設計會有腦裂、羊羣效應以及造成Zookeeper過載的隱患。


2.Kafka之Controller

在Kafka集羣中會有一個或者多個broker,其中有一個broker會被選舉爲控制器(Kafka Controller),它負責管理整個集羣中所有分區和副本的狀態。當某個分區的leader副本出現故障時,由控制器負責爲該分區選舉新的leader副本。當檢測到某個分區的ISR集合發生變化時,由控制器負責通知所有broker更新其元數據信息。當使用kafka-topics.sh腳本爲某個topic增加分區數量時,同樣還是由控制器負責分區的重新分配。

Kafka中的控制器選舉的工作依賴於Zookeeper,成功競選爲控制器的broker會在Zookeeper中創建/controller這個臨時(EPHEMERAL)節點,此臨時節點的內容參考如下:

{"version":1,"brokerid":0,"timestamp":"1529210278988"}

其中version在目前版本中固定爲1,brokerid表示稱爲控制器的broker的id編號,timestamp表示競選稱爲控制器時的時間戳。

在任意時刻,集羣中有且僅有一個控制器。每個broker啓動的時候會去嘗試去讀取/controller節點的brokerid的值,如果讀取到brokerid的值不爲-1,則表示已經有其它broker節點成功競選爲控制器,所以當前broker就會放棄競選;如果Zookeeper中不存在/controller這個節點,或者這個節點中的數據異常,那麼就會嘗試去創建/controller這個節點,當前broker去創建節點的時候,也有可能其他broker同時去嘗試創建這個節點,只有創建成功的那個broker纔會成爲控制器,而創建失敗的broker則表示競選失敗。每個broker都會在內存中保存當前控制器的brokerid值,這個值可以標識爲activeControllerId。

具備控制器身份的broker需要比其他普通的broker多一份職責,具體細節如下:

  • 監聽partition相關的變化。

爲Zookeeper中的/admin/reassign_partitions節點註冊PartitionReassignmentListener,用來處理分區重分配的動作。爲Zookeeper中的/isr_change_notification節點註冊IsrChangeNotificetionListener,用來處理ISR集合變更的動作。爲Zookeeper中的/admin/preferred-replica-election節點添加PreferredReplicaElectionListener,用來處理優先副本的選舉動作。

  • 監聽topic相關的變化。

爲Zookeeper中的/brokers/topics節點添加TopicChangeListener,用來處理topic增減的變化;爲Zookeeper中的/admin/delete_topics節點添加TopicDeletionListener,用來處理刪除topic的動作。

  • 監聽broker相關的變化。

爲Zookeeper中的/brokers/ids/節點添加BrokerChangeListener,用來處理broker增減的變化。

  • 從Zookeeper中讀取獲取當前所有與topic、partition以及broker有關的信息並進行相應的管理。

對於所有topic所對應的Zookeeper中的/brokers/topics/[topic]節點添加PartitionModificationsListener,用來監聽topic中的分區分配變化。

  • 啓動並管理分區狀態機和副本狀態機。
  • 更新集羣的元數據信息。
  • 如果參數auto.leader.rebalance.enable設置爲true,則還會開啓一個名爲“auto-leader-rebalance-task”的定時任務來負責維護分區的優先副本的均衡。

這個列表可能會讓讀者感到困惑,甚至完全不知所云。不要方~ 筆者這裏只是用來突出控制器的職能很多,而這些功能的具體細節會在後面的文章中做具體的介紹。

控制器在選舉成功之後會讀取Zookeeper中各個節點的數據來初始化上下文信息(ControllerContext),並且也需要管理這些上下文信息,比如爲某個topic增加了若干個分區,控制器在負責創建這些分區的同時也要更新上下文信息,並且也需要將這些變更信息同步到其他普通的broker節點中。不管是監聽器觸發的事件,還是定時任務觸發的事件,亦或者是其他事件(比如ControlledShutdown)都會讀取或者更新控制器中的上下文信息,那麼這樣就會涉及到多線程間的同步,如果單純的使用鎖機制來實現,那麼整體的性能也會大打折扣。針對這一現象,Kafka的控制器使用單線程基於事件隊列的模型,將每個事件都做一層封裝,然後按照事件發生的先後順序暫存到LinkedBlockingQueue中,然後使用一個專用的線程(ControllerEventThread)按照FIFO(First Input First Output, 先入先出)的原則順序處理各個事件,這樣可以不需要鎖機制就可以在多線程間維護線程安全。

在目前的新版本的設計中,只有Kafka Controller在Zookeeper上註冊相應的監聽器,其他的broker極少需要再監聽Zookeeper中的數據變化,這樣省去了很多不必要的麻煩。不過每個broker還是會對/controller節點添加監聽器的,以此來監聽此節點的數據變化(參考ZkClient中的IZkDataListener)。 

當/controller節點的數據發生變化時,每個broker都會更新自身內存中保存的activeControllerId。如果broker在數據變更前是控制器,那麼如果在數據變更後自身的brokerid值與新的activeControllerId值不一致的話,那麼就需要“退位”,關閉相應的資源,比如關閉狀態機、註銷相應的監聽器等。有可能控制器由於異常而下線,造成/controller這個臨時節點會被自動刪除;也有可能是其他原因將此節點刪除了。

當/controller節點被刪除時,每個broker都會進行選舉,如果broker在節點被刪除前是控制器的話,在選舉前還需要有一個“退位”的動作。如果有特殊需要,可以手動刪除/controller節點來觸發新一輪的選舉。當然關閉控制器所對應的broker以及手動向/controller節點寫入新的brokerid的所對應的數據同樣可以觸發新一輪的選舉。

3.參考

直擊Kafka的心臟——控制器

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章