1. 程式人生 > 實用技巧 >kafka常見面試題

kafka常見面試題

1.Kafka 中的 ISR(InSyncRepli)、OSR(OutSyncRepli)、AR(AllRepli)代表什麼?

  1、AR = ISR+OSR

ISR:

  kafka 使用多副本來保證訊息不丟失,多副本就涉及到kafka的複製機制,在一個超大規模的叢集中,時不時地這個點磁碟壞了,那個點cpu負載高了,出現各種各樣的問題,多個副本之間的複製,如果想完全自動化容錯,就要做一些考量和取捨了。我們舉個例子說明下運維中面對的複雜性,我們都知道 kafka 有個 ISR集合,我先說明下這個概念:

kafka不是完全同步,也不是完全非同步,是一種ISR機制:

1. leader會維護一個與其基本保持同步的Replica列表,該列表稱為ISR(in-sync Replica),每個Partition都會有一個ISR

,而且是由leader動態維護

2. 如果一個follower比一個leader落後太多,或者超過一定時間未發起資料複製請求,則leader將其重ISR中移除

3. 當ISR中所有Replica都向Leader傳送ACK時,leader才commit,這時候producer才能認為一個請求中的訊息都commit了。

  kafka中的副本機制是以分割槽粒度進行復制的,我們在kafka中建立 topic的時候,都可以設定一個複製因子,這個複製因子決定著分割槽副本的個數,如果leader 掛掉了,kafka 會把分割槽主節點failover到其他副本節點,這樣就能保證這個分割槽的訊息是可用的。leader節點負責接收producer 打過來的訊息,其他副本節點(follower)從主節點上拷貝訊息。

  存在的問題:

  從上面的情況來看,兩個引數看似已經足夠了,如果一個副本超過 replica.lag.time.max.ms 還沒有傳送fetch同步請求, 可以認為這個副本節點卡住了,然後踢出去,但是還有一種比較特殊的情況沒有考慮到,我們上文中設定 replica.lag.max.messages 為4,之所以設定為 4, 是我們已經知道 producer 每次請求打過來的訊息數都在 4 以下,如果我們的引數是作用於多個 topic 的情況,那麼這個 producer 最大打過來的訊息數目就不好估計了,或者說在經常出現流量抖動的情況下,就會出現一個什麼情況呢,我們還是使用例子說明:

  如果我們的 topic — foo 的 producer 因為流量抖動打過來一個 包含 4條訊息的請求,我們設定的 replica.lag.max.messages 還是為4, 這個時候,所有的 follower 都會因為超出落後條數被踢出 ISR集合。

  然後,因為 follower 是正常的,所以下一次 fetch 請求就會又追上 leader, 這時候就會再次加入 ISR 集合,如果經常性的抖動,就會不斷的移入移出ISR集合,會造成令人頭疼的 告警轟炸。

  kafka 給出的方案是這樣的,對 replica.lag.time.max.ms這個配置的含義做了增強,和之前一樣,如果 follower 卡住超過這個時間不傳送fetch請求, 會被踢出ISR集合,新的增強邏輯是,在 follower 落後 leader 超過eplica.lag.max.messages條訊息的時候,不會立馬踢出ISR 集合,而是持續落後超過replica.lag.time.max.ms時間,才會被踢出

2.Kafka 中的 HW、LEO 等分別代表什麼?

  

  • LEO:即日誌末端位移(log end offset),記錄了該副本底層日誌(log)中下一條訊息的位移值。注意是下一條訊息!也就是說,如果LEO=10,那麼表示該副本儲存了10條訊息,位移值範圍是[0, 9]。
  • High Watermark(高水位線)以下簡稱HW,表示訊息被leader和ISR內的follower都確認commit寫入本地log,所以在HW位置以下的訊息都可以被消費(不會丟失)。
Kafka複製協議有兩個階段,第一階段,follower從leader獲取到訊息;第二階段,在下一輪的RPC中向leader傳送fetch request確認收到訊息。假設其他的follower也都確認了,那麼leader會更新HW,並在接下來的RPC中響應給follower。
同時,在重啟一個follower時,這個follower可能會把日誌截斷到HW處(意味著此follower將會刪除一些訊息),然後從leader獲取訊息。

正式有與Kafka的複製協議分兩個階段,導致使用高水位會出現資料丟失和資料不一致的問題,下面我們分別講一下這兩種問題:

①資料丟失【Scenario 1: High Watermark Truncation followed by Immediate Leader Election】

假設有A、B兩個Broker,初始時B為leader,A從B中取到訊息m2,所以A中有訊息m2了,但是由於在下一輪RPC中,A才會更新自己的HW,所以此時A的HW沒變。如果這時候A重啟了,他擷取自己的日誌到HW併發送一個fetch request到B。不幸的是,B這時宕機了,A成了新的leader,那麼此時訊息m2就會永久的丟失了。

②資料不一致:【Scenario 2: Replica Divergence on Restart after Multiple Hard Failures】

假設我們有兩個Broker,初始時A是leader,B是follower。A接收到m2訊息,但B還沒來得及複製時,斷電了。過了一會,B重啟了,成為了leader,接收了m3訊息,HW+1。然後A重啟了,截斷日誌到高水位,但是此時的訊息卻出現了不一致。

在0.11版本使用leader epoch解決這兩個問題。

3.Kafka 中是怎麼體現訊息順序性的?

1、Kafka只能保證分割槽內訊息順序有序,無法保證全域性有序。

  • 生產者:通過分割槽的leader副本負責資料順序寫入,來保證訊息順序性。
  • 消費者:同一個分割槽內的訊息只能被一個group裡的一個消費者消費,保證分割槽內消費有序。

2、如何做到併發且全域性有序?

  整體思路】想辦法讓需要保證順序的資料傳送到同一個分割槽中,並增加生產者/消費者的併發度

  1. topic設定一個分割槽,傳送端和消費端開啟多執行緒生產和消費:簡單但有熱點瓶頸問題。
  2. topic設定多個分割槽,自定義傳送端的分割槽策略,資料傳送不同分割槽,消費時按傳送分割槽的順序消費,傳送和消費端都啟動多執行緒來提高併發度
    1. 自義分割槽器,使得訊息按分割槽號大小順序依次傳送相同數量大小的資料
    2. 傳送端和消費端啟動多個消費執行緒進行生產和消費
    3. 執行緒之間按分割槽號大小順序消費資料
    4. 【弊端】消費效能極大下降,無法真正併發

4.Kafka 中的分割槽器、序列化器、攔截器是否瞭解?它們之間的處理順序是什麼?

  分割槽器:根據鍵值確定訊息應該處於哪個分割槽中,預設情況下使用輪詢分割槽,可以自行實現分割槽器介面自定義分割槽邏輯
  序列化器:鍵序列化器和值序列化器,將鍵和值都轉為二進位制流 還有反序列化器 將二進位制流轉為指定型別資料
  攔截器:兩個方法 doSend()方法會在序列化之前完成 ,onAcknowledgement()方法在訊息確認或失敗時回撥。 可以新增多個攔截器按順序執行。
  呼叫順序: 攔截器doSend() -> 序列化器 -> 分割槽器

5.Kafka 生產者客戶端的整體結構是什麼樣子的?使用了幾個執行緒來處理?分別是什麼?

  Kafka 的 Producer 傳送訊息採用的是非同步傳送的方式。在訊息傳送的過程中,涉及到了兩個執行緒——main 執行緒和 Sender 執行緒,以及一個執行緒共享變數——RecordAccumulator。 main 執行緒將訊息傳送給 RecordAccumulator,Sender 執行緒不斷從 RecordAccumulator 中拉取 訊息(已經分好區)傳送到 Kafka broker

  https://www.cnblogs.com/wsw-seu/p/13458506.html

6.“消費組中的消費者個數如果超過 topic 的分割槽,那麼就會有消費者消費不到資料”這句 話是否正確?

正確,生產環境中這樣做浪費資源。

7.消費者提交消費位移時提交的是當前消費到的最新訊息的 offset 還是 offset+1?

  offset+1

下面這個例子,zk中,bbb主題,2個分割槽。還沒消費就會存一個0 offset。

8.有哪些情形會造成重複消費?

消費者 先處理訊息,後提交offset(可能失敗)

9.那些情景會造成訊息漏消費?

消費者 先提交offset,再處理訊息(可能失敗)

10.當你使用 kafka-topics.sh 建立(刪除)了一個 topic 之後,Kafka 背後會執行什麼邏輯?

1)會在 zookeeper 中的/brokers/topics 節點下建立一個新的 topic 節點,如:

/brokers/topics/first

2)觸發 Controller 的監聽程式
3)kafka Controller 負責 topic 的建立工作,並更新 metadata cache

11.topic 的分割槽數可不可以增加?如果可以怎麼增加?如果不可以,那又是為什麼?

可以增

當一個主題被建立之後,依然允許我們對其做一定的修改,比如修改分割槽個數、修改配置等,這個修改的功能就是由kafka-topics.sh指令碼中的alter指令所提供。我們首先來看如何增加主題的分割槽數。

以前面的主題topic-config為例,當前分割槽數為1,修改為3,示例如下:

注意上面提示的告警資訊:當主題中的訊息包含有key時(即key不為null),根據key來計算分割槽的行為就會有所影響。當topic-config的分割槽數為1時,不管訊息的key為何值,訊息都會發往這一個分割槽中;當分割槽數增加到3時,那麼就會根據訊息的key來計算分割槽號,原本發往分割槽0的訊息現在有可能會發往分割槽1或者分割槽2中。如此還會影響既定訊息的順序,所以在增加分割槽數時一定要三思而後行。對於基於key計算的主題而言,建議在一開始就設定好分割槽數量,避免以後對其進行調整。

12.topic 的分割槽數可不可以減少?如果可以怎麼減少?如果不可以,那又是為什麼?

目前Kafka只支援增加分割槽數而不支援減少分割槽數。比如我們將主題topic-config的分割槽數修改為1,就會報出InvalidPartitionException的異常。

比如刪除掉的分割槽中的訊息該作何處理?如果隨著分割槽一起消失則訊息的可靠性得不到保障;如果需要保留則又需要考慮如何保留。直接儲存到現有分割槽的尾部,訊息的時間戳就不會遞增,如此對於Spark、Flink這類需要訊息時間戳(事件時間)的元件將會受到影響;如果分散插入到現有的分割槽中,那麼在訊息量很大的時候,內部的資料複製會佔用很大的資源,而且在複製期間,此主題的可用性又如何得到保障?與

此同時,順序性問題、事務性問題、以及分割槽和副本的狀態機切換問題都是不得不面對的。反觀這個功能的收益點卻是很低,如果真的需要實現此類的功能,完全可以重新建立一個分割槽數較小的主題,然後將現有主題中的訊息按照既定的邏輯複製過去即可。

雖然分割槽數不可以減少,但是分割槽對應的副本數是可以減少的,這個其實很好理解,你關閉一個副本時就相當於副本數減少了。

13.Kafka 有內部的 topic 嗎?如果有是什麼?有什麼所用?

kafka在0.10.x版本後預設將消費者組的位移(offset)提交到自帶的topic__consumer_offsets裡面,當有消費者第一次消費kafka資料時就會自動建立,它的副本數不受叢集配置的topic副本數限制,分割槽數預設50(可以配置),預設壓縮策略為compact


14.Kafka 分割槽分配的概念?

當遇到“分割槽分配”這個字眼的時候,一定要記住有三處地方,分別是生產者傳送訊息、消費者消費訊息、建立主題

1、生產者的分割槽分配

  對於使用者而言,當呼叫send方法傳送訊息之後,訊息就自然而然的傳送到了broker中。其實在這一過程中,有可能還要經過攔截器、序列化器和分割槽器(Partitioner)的一系列作用之後才能被真正地發往broker。

  訊息在發往broker之前是需要確定它所發往的分割槽的,如果訊息ProducerRecord中指定了partition欄位,那麼就不需要分割槽器的作用,因為partition代表的就是所要發往的分割槽號。如果訊息       ProducerRecord中沒有指定partition欄位,那麼就需要依賴分割槽器,根據key這個欄位來計算partition的值。分割槽器的作用就是為訊息分配分割槽。   預設情況下,如果訊息的key不為null,那麼預設的分割槽器會對key進行雜湊(採用MurmurHash2演算法,具備高運算效能及低碰撞率),最終根據得到的雜湊值來計算分割槽號,擁有相同key的訊息會被寫入同一個分割槽。如果key為null,那麼訊息將會以輪詢的方式發往主題內的各個可用分割槽

2、消費者的分割槽分配

  在Kafka的預設規則中,每一個分割槽只能被同一個消費組中的一個消費者消費。消費者的分割槽分配是指為消費組中的消費者分配所訂閱主題中的分割槽。

Kafka自身提供了三種策略,分別為RangeAssignorRoundRobinAssignor以及StickyAssignor,其中RangeAssignor為預設的分割槽分配策略

3、broker端的分割槽分配

  生產者的分割槽分配是指為每條訊息指定其所要發往的分割槽,消費者中的分割槽分配是指為消費者指定其可以消費訊息的分割槽,而這裡的分割槽分配是指為叢集制定建立主題時的分割槽副本分配方案,即在哪個broker中建立哪些分割槽的副本。分割槽分配是否均衡會影響到Kafka整體的負載均衡,具體還會牽涉到優先副本等概念。

15.簡述 Kafka 的日誌目錄結構?

見深入理解kafka核心設計與實踐原理第5章日誌儲存
16.如果我指定了一個 offset,Kafka Controller 怎麼查詢到對應的訊息?

同上

17.聊一聊 Kafka Controller 的作用?

  Controller 作為 Kafka Server 端一個重要的元件,它的角色類似於其他分散式系統 Master 的角色,跟其他系統不一樣的是,Kafka 叢集的任何一臺 Broker 都可以作為 Controller,但是在一個叢集中同時只會有一個 Controller 是 alive 狀態。Controller 在叢集中負責的事務很多,比如:叢集 meta 資訊的一致性保證、Partition leader 的選舉、broker 上下線等都是由 Controller 來具體負責。

  

  Controller 是執行在 Broker 上的,任何一臺 Broker 都可以作為 Controller,但是一個叢集同時只能存在一個 Controller,也就意味著 Controller 與資料節點是在一起的,Controller 做的主要事情如下:

  1. Broker 的上線、下線處理;
  2. 新建立的 topic 或已有 topic 的分割槽擴容,處理分割槽副本的分配、leader 選舉;
  3. 管理所有副本的狀態機和分割槽的狀態機,處理狀態機的變化事件;
  4. topic 刪除、副本遷移、leader 切換等處理。


18.Kafka 中有那些地方需要選舉?這些地方的選舉策略又有哪些?

Kafka中的選舉大致可以分為三大類:控制器的選舉、分割槽leader的選舉以及消費者相關的選舉。

1、控制器的選舉

在Kafka叢集中會有一個或多個broker,其中有一個broker會被選舉為控制器(Kafka Controller),它負責管理整個叢集中所有分割槽和副本的狀態等工作。比如當某個分割槽的leader副本出現故障時,由控制器負責為該分割槽選舉新的leader副本。再比如當檢測到某個分割槽的ISR集合發生變化時,由控制器負責通知所有broker更新其元資料資訊。

Kafka Controller的選舉是依賴Zookeeper來實現的,在Kafka叢集中哪個broker能夠成功建立/controller這個臨時(EPHEMERAL)節點他就可以成為Kafka Controller。

2、分割槽leader的選舉

  分割槽leader副本的選舉由Kafka Controller 負責具體實施。當建立分割槽(建立主題或增加分割槽都有建立分割槽的動作)或分割槽上線(比如分割槽中原先的leader副本下線,此時分割槽需要選舉一個新的leader上線來對外提供服務)的時候都需要執行leader的選舉動作。

  基本思路是按照AR集合中副本的順序查詢第一個存活的副本,並且這個副本在ISR集合中。一個分割槽的AR集合在分配的時候就被指定,並且只要不發生重分配的情況,集合內部副本的順序是保持不變的,而分割槽的ISR集合中副本的順序可能會改變。注意這裡是根據AR的順序而不是ISR的順序進行選舉的。

  還有一些情況也會發生分割槽leader的選舉,比如當分割槽進行重分配(reassign)的時候也需要執行leader的選舉動作。這個思路比較簡單:從重分配的AR列表中找到第一個存活的副本,且這個副本在目前的ISR列表中。

  再比如當發生優先副本(preferred replica partition leader election)的選舉時,直接將優先副本設定為leader即可,AR集合中的第一個副本即為優先副本。

3、消費者相關的選舉

  組協調器GroupCoordinator需要為消費組內的消費者選舉出一個消費組的leader,這個選舉的演算法也很簡單,分兩種情況分析。如果消費組內還沒有leader,那麼第一個加入消費組的消費者即為消費組的leader。如果某一時刻leader消費者由於某些原因退出了消費組,那麼會重新選舉一個新的leader。

19.失效副本是指什麼?有那些應對措施?

  正常情況下,分割槽的所有副本都處於 ISR 集合中,但是難免會有異常情況發生,從而某些副本被剝離出 ISR 集合中。在 ISR 集合之外,也就是處於同步失效或功能失效(比如副本處於非存活狀態)的副本統稱為失效副本,失效副本對應的分割槽也就稱為同步失效分割槽,即 under-replicated 分割槽。

  可以參考https://www.cnblogs.com/luozhiyun/p/12079527.html
20.Kafka 的哪些設計讓它有如此高的效能?