1. Kafka控制器介紹
在Kafka集群中會有一個或多個broker,其中有一個broker會被選舉為控制器(Kafka Controller),它負責管理整個集群中所有分區和副本的狀態。當某個分區的leader副本(一個分區會有多個副本,其中只有leader副本對外提供讀寫服務)出現故障時,由控制器負責為該分區選舉新的leader副本。當檢測到某個分區的ISR集合發生變化時,由控制器負責通知所有broker更新其元數據信息。當為某個Topic增加分區數量時,由控制器負責分區的重新分配。
分區集合介紹:分區中的所有副本統稱為AR(Assigned Replicas)。所有與leader副本保持一定程度同步的副本(包括leader副本在內)組成ISR(In-Sync Replicas)。與leader副本同步滯后過多的副本(不包括leader副本)組成OSR(Out-of-Sync Replicas)。
leader副本負責維護和跟蹤ISR集合中所有follower副本的滯后狀態,當follower副本落后太多或失效時,leader副本會把它從ISR集合中剔除。當OSR集合中有follower副本“追上”了leader副本,那么leader副本會把它從OSR集合轉移至ISR集合。默認情況下,當leader副本發生故障時,只有在ISR集合中的副本才有資格被選舉為新的leader。
2. Kafka控制器選舉原理
Kafka中的控制器選舉工作依賴於Zookeeper,成功競選成為控制器的broker會在Zookeeper中創建/controller臨時(Ephemeral)節點
,此臨時節點的內容參考如下:
{"version":1,"brokerid":0,"timestamp":"1593330804078"}
其中version與Kafka版本相關,對同一個Kafka版本來說為固定值。brokerid表示成為控制器的broker的id編號,timestamp表示競選成為控制器時的時間戳(精確到毫秒)。
在任意時刻,集群中有且只有一個控制器。每個broker啟動的時候會去嘗試讀取/controller
節點的brokerid的值,如果讀取到的brokerid的值不為-1,表示已經有其他broker節點成功競選為控制器,所以當前broker就會放棄競選;如果Zookeeper中不存在/controller
節點,或者這個節點的數據異常,那么就會嘗試去創建/controller
節點。當前broker去創建節點的時候,也有可能有其他broker同時去嘗試創建這個節點,只有創建成功的那個broker才會成為控制器。每個broker都會在內存中保存當前控制器的brokerid值,這個值可以標識為activeControllerId。
Zookeeper中還有一個與控制器有關的/controller_epoch
節點,這個節點是持久(Persistent)節點
,節點中存放的是一個整型的controller_epoch值。controller_epoch值用於記錄控制器發生變更的次數,即記錄當前的控制器是第幾代控制器,我們也可以稱之為“控制器紀元
”。
controller_epoch的初始值為1,即集群中的第一個控制器的紀元為1,當控制器發生變更時,每選出一個新的控制器就將該字段值加1。每個和控制器交互的請求都會攜帶controller_epoch這個字段,如果請求的controller_epoch值小於內存中的controller_epoch值,則認為這個請求是向已經過期的控制器發送的請求,那么這個請求會被認定為無效的請求。如果請求的controller_epoch值大於內存中的controller_epoch值,那么說明已經有新的控制器當選了(也就是說接收到這種請求的broker已經不再是控制器了)。由此可見,Kafka通過controller_epoch來保證控制器的唯一性,進而保證相關操作的一致性。
具備控制器身份的broker需要比其他普通的broker多一份職責,具體細節如下:
- 監聽分區的變化。
- 監聽主題的變化。
- 監聽broker相關的變化。
- 從Zookeeper中讀取獲取當前所有與主題、分區及broker有關的信息並進行相應的管理。
- 啟動並管理分區狀態機和副本狀態機。
- 更新集群的元數據信息。
當/controller
節點的數據發生變化時,每個broker都會更新自身內存中保存的activeControllerId。如果broker在數據變更前是控制器,在數據變更后自身的brokerid值與新的activeControllerId值不一致,那么就需要“退位”,關閉相應的資源,比如關閉狀態機、注銷相應的監聽器等。有可能控制器由於異常而下線,造成/controller
這個臨時節點被自動刪除;也有可能是其他原因將此節點刪除了。
當/controller
節點被刪除時,每個broker都會進行選舉,如果broker在節點被刪除前是控制器,那么在選舉前還需要有一個“退位”的動作。如果有特殊需要,則可以手動刪除/controller
節點來觸發新一輪的選舉。當然關閉控制器所對應的broker,以及手動向/controller
節點寫入新的brokerid的所對應的數據,同樣可以觸發新一輪的選舉。
3. 總結
Kafka控制器選擇的流程並不復雜,但是考慮的各種邊界條件還是比較周到的,程序的健壯性比較好。有時候我們需要根據業務場景去設計或者調整某種分布式集群,Kafka控制器的選舉也可以是一個很好的借鑒,尤其是/controller_epoch
的設計,考慮到了控制器可能會因為某種原因過時,保證了控制器的唯一性。
4. 參考文獻
《深入理解Kafka:核心設計與實踐原理》