Kafka 的 10 道基礎面試題

1. Kafka 是什麼?

Kafka 起初是一個多分區、多副本且基於 ZooKeeper 協調的分佈式消息系統,現已被定位爲一個分佈式流式處理平臺

2. Kafka 的架構瞭解嗎?

建議按以下順序講述:

  1. Kafka 是基於發佈 / 訂閱的消息系統(引出 Producer、Consumer 和 Broker),所以存在三個角色 Producer(生產消息)、Broker(Kafka 實例)和 Consumer(消費消息)。

  2. 生產者會將消息推送到 Kafka 的某個 Topic 上,以此區分消息

  3. 爲了高可用性,通過在集羣上部署多個 Broker,一個 Topic 將以多副本的形式分佈在多個 Broker 上,基於 ZK 選出一個 Leader 副本,而其他 Follower 副本則負責同步 Leader 副本,避免單點問題。

  4. 爲了高吞吐量,再將 Topic 劃分成多個分區,可讓 Topic 的吞吐量不受單機限制。

  5. 爲了高吞吐量,對於多個分區,單個消費者也可變成多個,形成消費組,一個分區由一個消費者負責。

3. 瞭解其他 MQ 嗎?有什麼不同?

有了解 RadbbitMQ,RabbitMQ 由於有消息確認機制,所以數據丟失的可能性更小適合嚴格的金融場景

而 Kafka 的優勢則在於其吞吐量更大適合處理活躍的流式數據

4. 如何保證消息的有序性?

Kafka 只能保證局部有序,即只能保證一個分區裏的消息有序。而其具體實現是通過生產者爲每個分區的消息維護一個發送隊列,我們需要將保證順序的消息都發送到同一個分區中。並且由於 Kafka 會同時發送多個消息,所以還需指定 max.in.flight.requests.per.connection 爲 1,保證前一個消息發送成功,後一個消息纔開始發送。

max.in.flight>1 時能保證有序性嗎?

可以,設置冪等能保證。不過 max.in.flight 不能大於 5。這是因爲 Broker 端只會緩存最近 5 個 Batch 的 SequenceNumber,例如我們發送 1 到 6 的報文,其中 1 發送失敗,2-5 發送成功,Broker 緩存下來,當 1 重試時,Broker 檢查到 1 小於緩存中的最小序號,會拋出異常,而 Producer 將重試發送 1 超過最多次數或超時,影響性能。

冪等如何保證有序性?

通過引入 ProduceID(PID) SequenceNumber 的概念,每個 Producer 在初始化時被分配唯一的 PID,而 <Topic,Partition> 的每條有一個從 0 單調遞增的 SequenceNumber。在發送消息時,由以下三點保證:

  1. 驗證序號連續:Broker 會驗證 Batch 的 SequenceNumber 是否連續,若不連續,拋出異常;

  2. 重試時,batch 放置正確位置:Producer 請求重試時,會根據 SequenceNumber 將 Batch 放在隊列中的合適位置;

  3. 重試時,max.in.flight 調爲 1:當請求重試時,會把 max.in.flight 動態調整爲 1,保證請求序號小的先發送成功。

5. 如何保證冪等?

Kafka 具有冪等機制,但默認不開啓,需要設置 enable.idempotence 爲 true 開啓。但只能實現單會話、單分區上的冪等。

爲什麼只能實現單會話上的冪等?

在 Producer 初始化時,Kafka 會爲其重新分配一個新的 PID,而 Broker 端在維護 SequenceNumber 時是以 <ProducerID, Topic, Partition> 作爲維度,因此當 PID 變化時 Broker 將無法獲得之前的狀態信息,無法做到單會話上的不丟不衝。

如何實現跨會話冪等?

事務機制,通過引入 TransactionIDEpoch。不同於 PID 是由內部進行分配,TrasactionID 是由用戶提供。而 TransactionID 與 PID 會一一對應,這樣當 Producer 宕機時,集羣啓動一個新的 Producer,在初始化時可以通過 TransactionID 獲得 PID,便能繼續工作。同時會被分配一個單調遞增的 Epoch,來保證當舊 Producer 恢復後可能生產出重複消息,Broker 段會拒絕舊 Epoch 的消息。

6. 支持什麼語義?

三種語義:

  1. 最多一次 (At Most Once):不會重複發送,可能消息丟失

  2. 最少一次 (At Least Once):會重複發送,消息不會丟失 (默認)

  3. 只有一次 (Exactly Once):不會重複發送,消息不會丟失

7. 如何保證 Exactly Once 語義?

  1. Producer 冪等 + At Least Once = Exactly Once(單分區、單會話)

  2. 事務可實現跨分區、跨會話的 Exactly Once 語義

8. 消息重複的場景有哪些?如何解決?

Broker 在寫入消息後,Producer 沒有收到成功的響應。

解決方法:

  1. 啓動冪等;

  2. acks = 0,不重試,但會丟失消息。

9. 消息丟失的場景有哪些?如何解決?

(一)Producer 端丟失消息

在調用 send 方法時,由於網絡原因發送失敗。

解決辦法:設置 retries 爲一個合適的值,一般爲 3,此外重試的間隔不能太小,避免網絡一次波動的區間就把三次重試用完了。

(二)Consumer 端丟失消息

自動提交 offset 時,可能未來得及處理消息,但 offset 已被提交。

解決辦法:關閉自動提交,消費完後手動提交 offset。

(三)Broker 端丟失消息

Leader 副本所在的 Broker 宕機,而 Follower 副本還沒有完全通過 Leader

解決辦法:

  1. 設置 acks =-1 或 ALL,保證 Follower 副本寫入消息;

  2. replication.factor > 3,保證分區至少有 3 個副本,冗餘消息;

  3. min.insync.replicas >1,消息至少被寫入 2 個副本才認爲成功;

  4. unclean.leader.election.enable=false,避免從非 ISR 中選舉 Leader。

10. Kafka 吞吐量高的原因

  1. 順序寫:寫讀數據時,數據直接追加在文件的末尾;

  2. MMAP:數據不實時寫入硬盤,以此提高 IO 效率;

  3. 零拷貝:讀數據時,使用了 sendfile,磁盤文件讀到 OS 內核緩衝區後,直接轉到 socket buffer 進行網絡發送;

  4. 批量壓縮:消耗少量的 CPU 資源,提高 IO 效率;

一句話貫穿:Kafka 把所有的消息都變成一個個批量的文件,並且進行合理的批量壓縮,減少網絡 IO 的損耗,寫入是通過 MMAP 提高 IO 效率,同時由於單個分區是順序寫文件,所以速度最優;讀取數據的時候配合 sendfile 直接暴力輸出。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/4szlgbdSLI7gIsFvxxY7sA