“請你簡述一下Kafka中的分割槽分配”,當面試官問你這個問題的時候,你會怎麼回答?其實,這道題目裡面就暗藏洶湧,因為Kafka中的分割槽分配在多處出現,而這個問題的表述方式是在潛意識裡暗示你回答一種,這樣在你自認為很完美的回答完這個問題之後,面試官會冷不丁的來一句:還有呢?
當你回答完一個點的時候,面試官來一句還有呢,當你再補上一個的時候,他還是會來一句還有呢,就算你又補上第三個的時候,他還是會來一句還有呢?這個時候你會不會一臉懵逼?
今天就針對這個問題來告訴大家怎麼樣回答才能嚴絲合縫地搶得先機。
在Kafka中,分割槽分配是一個很重要的概念,卻往往會被讀者忽視,它會影響Kafka整體的效能均衡。當遇到“分割槽分配”這個字眼的時候,一定要記住有三處地方,分別是生產者傳送訊息、消費者消費訊息和建立主題。雖然這三處的對應操作都可以被稱之為“分割槽分配”,但是其實質上所包含的內容卻並不相同。
在面對開篇的問題的時候,不如一下就進行總結性的陳詞,說有三處,第一、第二、第三balabala,當真的讓你講完三處的時候,時間也就差不多了。。聰明的面試官看到你一上來就做了一個規劃總結,那他頂多也就讓你說說你最熟悉的一種,其實說不定內心已經確認你是對的人。
下面針對這三處做個講解。不過本文旨在羅列相關知識點,進行相關性的科普描述,讓讀者可以追根溯源,但並不陳述具體細節,因為細節很多,篇幅有限,如有需要請詳參老朽的《深入理解Kafka》。
生產者的分割槽分配
對於使用者而言,當呼叫send方法傳送訊息之後,訊息就自然而然的傳送到了broker中。其實在這一過程中,有可能還要經過攔截器、序列化器和分割槽器(Partitioner)的一系列作用之後才能被真正地發往broker。
producer.send(record);
複製程式碼
訊息在發往broker之前是需要確定它所發往的分割槽的,如果訊息ProducerRecord中指定了partition欄位,那麼就不需要分割槽器的作用,因為partition代表的就是所要發往的分割槽號。如果訊息ProducerRecord中沒有指定partition欄位,那麼就需要依賴分割槽器,根據key這個欄位來計算partition的值。分割槽器的作用就是為訊息分配分割槽。
Kafka中提供的預設分割槽器是DefaultPartitioner,它實現了Partitioner介面(使用者可以實現這個介面來自定義分割槽器),其中的partition方法就是用來實現具體的分割槽分配邏輯:
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster);
複製程式碼
預設情況下,如果訊息的key不為null,那麼預設的分割槽器會對key進行雜湊(採用MurmurHash2演算法,具備高運算效能及低碰撞率),最終根據得到的雜湊值來計算分割槽號,擁有相同key的訊息會被寫入同一個分割槽。如果key為null,那麼訊息將會以輪詢的方式發往主題內的各個可用分割槽。
注意:如果key不為null,那麼計算得到的分割槽號會是所有分割槽中的任意一個;如果key為null並且有可用分割槽,那麼計算得到的分割槽號僅為可用分割槽中的任意一個,注意兩者之間的差別。
消費者的分割槽分配
在Kafka的預設規則中,每一個分割槽只能被同一個消費組中的一個消費者消費。消費者的分割槽分配是指為消費組中的消費者分配所訂閱主題中的分割槽。
如圖所示,某個主題中共有4個分割槽(Partition):P0、P1、P2、P3。有兩個消費組A和B都訂閱了這個主題,消費組A中有4個消費者(C0、C1、C2和C3),消費組B中有2個消費者(C4和C5)。按照Kafka預設的規則,最後的分配結果是消費組A中的每一個消費者分配到1個分割槽,消費組B中的每一個消費者分配到2個分割槽,兩個消費組之間互不影響。每個消費者只能消費所分配到的分割槽中的訊息。
對於消費者的分割槽分配而言,Kafka自身提供了三種策略,分別為RangeAssignor、RoundRobinAssignor以及StickyAssignor,其中RangeAssignor為預設的分割槽分配策略,至於這三種策略具體代表什麼含義,可以去查閱相關資料,比如《深入理解Kafka》,嘿嘿。當然也可以通過實現ParitionAssignor介面來自定義分割槽分配策略。
在消費組中如果有多個消費者,那麼這些消費者又可能會採用不同的分配策略,那麼最後怎麼“拍板”使用哪一種具體的分配策略呢?
對於這裡,我想留一道思考題給大家:在Kafka的預設規則中,每一個分割槽只能被同一個消費組中的一個消費者消費,那麼這個規則可以被打破麼?如果可以,怎麼打破?打破的收益又是什麼?
broker端的分割槽分配
生產者的分割槽分配是指為每條訊息指定其所要發往的分割槽,消費者中的分割槽分配是指為消費者指定其可以消費訊息的分割槽,而這裡的分割槽分配是指為叢集制定建立主題時的分割槽副本分配方案,即在哪個broker中建立哪些分割槽的副本。分割槽分配是否均衡會影響到Kafka整體的負載均衡,具體還會牽涉到優先副本等概念。
在建立主題時,如果使用了replica-assignment引數,那麼就按照指定的方案來進行分割槽副本的建立;如果沒有使用replica-assignment引數,那麼就需要按照內部的邏輯來計算分配方案了。使用kafka-topics.sh指令碼建立主題時的內部分配邏輯按照機架資訊劃分成兩種策略:未指定機架資訊和指定機架資訊。如果叢集中所有的broker節點都沒有配置broker.rack引數,或者使用disable-rack-aware引數來建立主題,那麼採用的就是未指定機架資訊的分配策略,否則採用的就是指定機架資訊的分配策略。
歡迎支援筆者小冊:
歡迎支援筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的部落格。