Kafka 的 10 道基礎面試題
1. Kafka 是什麼?
Kafka 起初是一個多分區、多副本且基於 ZooKeeper 協調的分佈式消息系統,現已被定位爲一個分佈式流式處理平臺。
2. Kafka 的架構瞭解嗎?
建議按以下順序講述:
-
Kafka 是基於發佈 / 訂閱的消息系統(引出 Producer、Consumer 和 Broker),所以存在三個角色 Producer(生產消息)、Broker(Kafka 實例)和 Consumer(消費消息)。
-
生產者會將消息推送到 Kafka 的某個 Topic 上,以此區分消息。
-
爲了高可用性,通過在集羣上部署多個 Broker,一個 Topic 將以多副本的形式分佈在多個 Broker 上,基於 ZK 選出一個 Leader 副本,而其他 Follower 副本則負責同步 Leader 副本,避免單點問題。
-
爲了高吞吐量,再將 Topic 劃分成多個分區,可讓 Topic 的吞吐量不受單機限制。
-
爲了高吞吐量,對於多個分區,單個消費者也可變成多個,形成消費組,一個分區由一個消費者負責。
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。在發送消息時,由以下三點保證:
-
驗證序號連續:Broker 會驗證 Batch 的 SequenceNumber 是否連續,若不連續,拋出異常;
-
重試時,batch 放置正確位置:Producer 請求重試時,會根據 SequenceNumber 將 Batch 放在隊列中的合適位置;
-
重試時,max.in.flight 調爲 1:當請求重試時,會把 max.in.flight 動態調整爲 1,保證請求序號小的先發送成功。
5. 如何保證冪等?
Kafka 具有冪等機制,但默認不開啓,需要設置 enable.idempotence 爲 true 開啓。但只能實現單會話、單分區上的冪等。
爲什麼只能實現單會話上的冪等?
在 Producer 初始化時,Kafka 會爲其重新分配一個新的 PID,而 Broker 端在維護 SequenceNumber 時是以 <ProducerID, Topic, Partition> 作爲維度,因此當 PID 變化時 Broker 將無法獲得之前的狀態信息,無法做到單會話上的不丟不衝。
如何實現跨會話冪等?
事務機制,通過引入 TransactionID 和 Epoch。不同於 PID 是由內部進行分配,TrasactionID 是由用戶提供。而 TransactionID 與 PID 會一一對應,這樣當 Producer 宕機時,集羣啓動一個新的 Producer,在初始化時可以通過 TransactionID 獲得 PID,便能繼續工作。同時會被分配一個單調遞增的 Epoch,來保證當舊 Producer 恢復後可能生產出重複消息,Broker 段會拒絕舊 Epoch 的消息。
6. 支持什麼語義?
三種語義:
-
最多一次 (At Most Once):不會重複發送,可能消息丟失
-
最少一次 (At Least Once):會重複發送,消息不會丟失 (默認)
-
只有一次 (Exactly Once):不會重複發送,消息不會丟失
7. 如何保證 Exactly Once 語義?
-
Producer 冪等 + At Least Once = Exactly Once(單分區、單會話)
-
事務可實現跨分區、跨會話的 Exactly Once 語義
8. 消息重複的場景有哪些?如何解決?
Broker 在寫入消息後,Producer 沒有收到成功的響應。
解決方法:
-
啓動冪等;
-
acks = 0,不重試,但會丟失消息。
9. 消息丟失的場景有哪些?如何解決?
(一)Producer 端丟失消息
在調用 send 方法時,由於網絡原因發送失敗。
解決辦法:設置 retries 爲一個合適的值,一般爲 3,此外重試的間隔不能太小,避免網絡一次波動的區間就把三次重試用完了。
(二)Consumer 端丟失消息
自動提交 offset 時,可能未來得及處理消息,但 offset 已被提交。
解決辦法:關閉自動提交,消費完後手動提交 offset。
(三)Broker 端丟失消息
Leader 副本所在的 Broker 宕機,而 Follower 副本還沒有完全通過 Leader
解決辦法:
-
設置 acks =-1 或 ALL,保證 Follower 副本寫入消息;
-
replication.factor > 3,保證分區至少有 3 個副本,冗餘消息;
-
min.insync.replicas >1,消息至少被寫入 2 個副本才認爲成功;
-
unclean.leader.election.enable=false,避免從非 ISR 中選舉 Leader。
10. Kafka 吞吐量高的原因
-
順序寫:寫讀數據時,數據直接追加在文件的末尾;
-
MMAP:數據不實時寫入硬盤,以此提高 IO 效率;
-
零拷貝:讀數據時,使用了 sendfile,磁盤文件讀到 OS 內核緩衝區後,直接轉到 socket buffer 進行網絡發送;
-
批量壓縮:消耗少量的 CPU 資源,提高 IO 效率;
一句話貫穿:Kafka 把所有的消息都變成一個個批量的文件,並且進行合理的批量壓縮,減少網絡 IO 的損耗,寫入是通過 MMAP 提高 IO 效率,同時由於單個分區是順序寫文件,所以速度最優;讀取數據的時候配合 sendfile 直接暴力輸出。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/4szlgbdSLI7gIsFvxxY7sA