面試官在考查你Kafka知識的時候很可能會故弄玄虛的問你一下:Kafka中的選舉時怎麼回事?除非問你具體的哪種選舉,否則問這種問題的面試官多半也是對Kafka一知半解,這個時候就是“弄死”他的時候。當然如果你沒有一定的知識儲備,那麼就是你被“弄死”的時候。
一般問這個問題,那麼他肯定知道其中的一種,比如分割槽leader的選舉。所謂分割槽leader的選舉就是當ISR中的leader副本歇菜了,再重新選舉一個的過程。對於這個問題就是你反客為主的機會,因為Kafka中的選舉有多處,可不止分割槽leader的選舉這一處,就算指明問分割槽leader的選舉,那麼也需要分4種情況具體分析。而這裡面的細節是大多數人不甚明瞭的。
Kafka中的選舉大致可以分為三大類:控制器的選舉、分割槽leader的選舉以及消費者相關的選舉,這裡還可以具體細分為7個小類。我們一一來過一下,本文只是簡單羅列下大致的內容,至於內部具體的細節邏輯就需要靠讀者自己去探索啦。虐人還是被虐就靠你的自驅力了。
控制器的選舉
在Kafka叢集中會有一個或多個broker,其中有一個broker會被選舉為控制器(Kafka Controller),它負責管理整個叢集中所有分割槽和副本的狀態等工作。比如當某個分割槽的leader副本出現故障時,由控制器負責為該分割槽選舉新的leader副本。再比如當檢測到某個分割槽的ISR集合發生變化時,由控制器負責通知所有broker更新其後設資料資訊。
Kafka Controller的選舉是依賴Zookeeper來實現的,在Kafka叢集中哪個broker能夠成功建立/controller這個臨時(EPHEMERAL)節點他就可以成為Kafka Controller。
這裡需要說明一下的是Kafka Controller的實現還是相當複雜的,涉及到各個方面的內容,如果你掌握了Kafka Controller,你就掌握了Kafka的“半壁江山”。篇幅所限,這裡就不一一展開了,有興趣的讀者可以查閱一下《深入理解Kafka》中第6章的相關內容。
分割槽leader的選舉
這裡不說什麼一致性協議(PacificA)相關的內容,只講述具體的選舉內容。
分割槽leader副本的選舉由Kafka Controller 負責具體實施。當建立分割槽(建立主題或增加分割槽都有建立分割槽的動作)或分割槽上線(比如分割槽中原先的leader副本下線,此時分割槽需要選舉一個新的leader上線來對外提供服務)的時候都需要執行leader的選舉動作。
基本思路是按照AR集合中副本的順序查詢第一個存活的副本,並且這個副本在ISR集合中。一個分割槽的AR集合在分配的時候就被指定,並且只要不發生重分配的情況,集合內部副本的順序是保持不變的,而分割槽的ISR集合中副本的順序可能會改變。注意這裡是根據AR的順序而不是ISR的順序進行選舉的。這個說起來比較抽象,有興趣的讀者可以手動關閉/開啟某個叢集中的broker來觀察一下具體的變化。
還有一些情況也會發生分割槽leader的選舉,比如當分割槽進行重分配(reassign)的時候也需要執行leader的選舉動作。這個思路比較簡單:從重分配的AR列表中找到第一個存活的副本,且這個副本在目前的ISR列表中。
再比如當發生優先副本(preferred replica partition leader election)的選舉時,直接將優先副本設定為leader即可,AR集合中的第一個副本即為優先副本。
Kafka中有很多XX副本的稱呼,如果不是很瞭解,可以關注本系列的下一篇《Kafka科普系列 | Kafka中到底有多少種副本?》
還有一種情況就是當某節點被優雅地關閉(也就是執行ControlledShutdown)時,位於這個節點上的leader副本都會下線,所以與此對應的分割槽需要執行leader的選舉。這裡的具體思路為:從AR列表中找到第一個存活的副本,且這個副本在目前的ISR列表中,與此同時還要確保這個副本不處於正在被關閉的節點上。
消費者相關的選舉
對於這部分內容的理解,額。。如果你對消費者、消費組、消費者協調器以及組協調器不甚理解的話,那麼。。。職能毛遂自薦《深入理解Kafka》一書了,嘿嘿。
組協調器GroupCoordinator需要為消費組內的消費者選舉出一個消費組的leader,這個選舉的演算法也很簡單,分兩種情況分析。如果消費組內還沒有leader,那麼第一個加入消費組的消費者即為消費組的leader。如果某一時刻leader消費者由於某些原因退出了消費組,那麼會重新選舉一個新的leader,這個重新選舉leader的過程又更“隨意”了,相關程式碼如下:
//scala code.
private val members = new mutable.HashMap[String, MemberMetadata]
var leaderId = members.keys.head
複製程式碼
解釋一下這2行程式碼:在GroupCoordinator中消費者的資訊是以HashMap的形式儲存的,其中key為消費者的member_id,而value是消費者相關的後設資料資訊。leaderId表示leader消費者的member_id,它的取值為HashMap中的第一個鍵值對的key,這種選舉的方式基本上和隨機無異。總體上來說,消費組的leader選舉過程是很隨意的。
插播:近日發現文章被盜的厲害,發文幾個小時文章就在各大入口網站上出現,全都是標的原創。雖然沒有能力制止,但是我發現大多不仔細看直接抄的(有連我下面的公眾號二維碼也抄了去的,當然也有用PS來P掉我圖片水印的雞賊操作),所以機智的我。。不如在文章中插播一下我的書,讓他們盜了去也好替我宣傳宣傳。我是皮的很~~
到這裡就結束了嗎?還有分割槽分配策略的選舉呢。
許你對此有點陌生,但是用過Kafka的同學或許對partition.assignment.strategy(取值為RangeAssignor、RoundRobinAssignor、StickyAssignor等)這個引數並不陌生。每個消費者都可以設定自己的分割槽分配策略,對消費組而言需要從各個消費者呈報上來的各個分配策略中選舉一個彼此都“信服”的策略來進行整體上的分割槽分配。這個分割槽分配的選舉並非由leader消費者決定,而是根據消費組內的各個消費者投票來決定的。至於具體的細節麼。。。嘿嘿。
歡迎支援筆者小冊:《圖解Kafka之實戰指南》和《圖解Kafka之核心原理》
歡迎支援筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的部落格。