Kafka 核心知識點靈魂 16 問

語言: CN / TW / HK

大家好,我是夢想家 Alex,今天為大家帶來面試過程中關於 Kafka 核心知識靈魂 16 問 ~ 內容較豐富,建議轉發收藏。

1、為什麼要使用 Kafka ?

  • 緩衝和削峰

上游資料時有突發流量,下游可能扛不住,或者下游沒有足夠多的機器來保證冗餘,kafka 在中間可以起到一個緩衝的作用,把訊息暫存在 kafka 中,下游服務就可以按照自己的節奏進行慢慢處理。

  • 解耦和擴充套件性:

專案開始的時候,並不能確定具體需求。訊息佇列可以作為一個介面層,解耦重要的業務流程。只需要遵守約定,針對資料程式設計即可獲取擴充套件能力。

  • 冗餘:

可以採用一對多的方式,一個生產者釋出訊息,可以被多個訂閱 topic 的服務消費到,供多個毫無關聯的業務使用。健壯性: 訊息佇列可以堆積請求,所以消費端業務即使短時間死掉,也不會影響主要業務的正常進行。

  • 非同步通訊:

很多時候,使用者不想也不需要立即處理訊息。訊息佇列提供了非同步處理機制,允許使用者把一個訊息放入佇列,但並不立即處理它。想向佇列中放入多少訊息就放多少,然後在需要的時候再去處理它們 。

2、Kafka 消費過的訊息如何再消費?

kafka 消費訊息的 offset 是定義在 zookeeper 中的, 如果想重複消費 kafka 的訊息, 可以在 redis 中自己記錄 offset 的 checkpoint 點(n 個),當想重複消費訊息時,通過讀取 redis 中的 checkpoint 點進行 zookeeper 的 offset 重設,這樣就可以達到重複消費訊息的目的了 。

3、kafka 的資料是放在磁碟上還是記憶體上,為什麼速度會快?

kafka 使用的是磁碟儲存。

速度快是因為:

  • 順序寫入:

因為硬碟是機械結構,每次讀寫都會定址->寫入,其中定址是一個“機械動作”,它是耗時的。所以硬碟 “討厭”隨機 I/O, 喜歡順序 I/O。為了提高讀寫硬碟的速度,Kafka 就是使用順序 I/O。

  • Memory Mapped Files(記憶體對映檔案):

64 位作業系統中一般可以表示 20G 的資料檔案,它的工作原理是直接利用作業系統的 Page 來實現檔案到實體記憶體的直接對映。完成對映之後你對實體記憶體的操作會被同步到硬碟上。

  • Kafka 高效檔案儲存設計:

Kafka 把 topic 中一個 parition 大檔案分成多個小檔案段,通過多個小檔案段,就容易定期清除或刪除已經消費完檔案,減少磁碟佔用。通過索引資訊可以快速定位 message 和確定 response 的 大 小。通過 index 元資料全部對映到 memory(記憶體對映檔案),可以避免 segment file 的 IO 磁碟操作。通過索引檔案稀疏儲存,可以大幅降低 index 檔案元資料佔用空間大小。

4、Kafka 資料怎麼保障不丟失

這裡需要分成三個點說,一個是生產者端,一個消費者端,一個 broker 端 。

  • 生產者資料不丟失

kafka 的 ack 機制:在 kafka 傳送資料的時候,每次傳送訊息都會有一個確認反饋機制,確保訊息正常的能夠被收到,其中狀態有 0,1,-1。

如果是同步模式:

ack 設定為 0,風險很大,一般不建議設定為 0。即使設定為 1,也會隨著 leader 宕機丟失資料。所以如果要嚴格保證生產端資料不丟失,可設定為-1 。

如果是非同步模式:

也會考慮 ack 的狀態,除此之外,非同步模式下的有個 buffer,通過 buffer 來進行控制資料的傳送,有兩個值來進行控制,時間閾值與訊息的數量閾值,如果 buffer 滿了資料還沒有傳送出去,有個選項是配置是否立即清空 buffer。可以設定為-1,永久阻塞, 也就資料不再生產。非同步模式下,即使設定為-1。也可能因為程式設計師的不科學操作,操作資料丟失,比如 kill -9,但這是特別的例外情況。

注:ack=0:producer 不等待 broker 同步完成的確認,繼續傳送下一條(批)資訊。ack=1(預設):producer 要等待 leader 成功收到資料並得到確認,才傳送下一條 message。ack=-1:producer 得到 follwer 確認,才傳送下一條資料。

  • 消費者資料不丟失通過 offset commit 來保證資料的不丟失,kafka 自己記錄了每次消費的 offset 數值, 下次繼續消費的時候,會接著上次的 offset 進行消費。

而 offset 的資訊在 kafka0.8 版本之前儲存在 zookeeper 中,在 0.8 版本之後儲存到 topic 中,即使消費者在執行過程中掛掉了,再次啟動的時候會找到 offset 的值,找到之前消費訊息的位置,接著消費,由於 offset 的資訊寫入的時候並不是每條訊息消費完成後都寫入的,所以這種情況有可能會造成重複消費,但是不會丟失訊息 。

唯一例外的情況是,我們在程式中給原本做不同功能的兩個 consumer 組設定 。

KafkaSpoutConfig.bulider.setGroupid 的時候設定成了一樣的 groupid,這種情況會導致這兩個組共享同一份資料,就會產生組 A 消費 partition1,partition2 中的訊息,組 B 消費 partition3 的訊息,這樣每個組消費的訊息都會丟失,都是不完整的。為了保證每個組都獨享一份訊息資料,groupid 一定不要重複才行。

  • kafka 叢集中的 broker 的資料不丟失

每個 broker 中的 partition 我們一般都會設定有 replication(副本)的個數,生產者寫入的時候首先根據分發策略(有 partition 按 partition,有 key 按 key,都沒有輪詢)寫入到 leader 中,follower(副本)再跟 leader 同步資料,這樣有了備份,也可以保證訊息資料的不丟失 。

5、kafka 資料分割槽和消費者的關係?

每個分割槽只能由同一個消費組內的一個消費者(consumer)來消費,可以由不同的消費組的消費者來消費,同組的消費者則起到併發的效果 。

6、採集資料為什麼選擇 kafka?

在採集層,主要可以使用 Flume, Kafka 等技術 。

Flume:Flume 是管道流方式,提供了很多的預設實現,讓使用者通過引數部署,及擴充套件 API 。

Kafka:Kafka 是一個可持久化的分散式的訊息佇列。 Kafka 是一個非常通用的系統。你可以有許多生產者和很多的消費者共享多個主題 Topics 。

相比之下,Flume 是一個專用工具被設計為旨在往 HDFS,HBase 傳送資料。它對 HDFS 有特殊的優化,並且集成了 Hadoop 的安全特性。

所以,Cloudera 建議如果資料被多個系統消費的話,使用 kafka;如果資料被設計給 Hadoop 使用,使用 Flume。

7、kafka 的資料 offset 讀取流程

連線 ZK 叢集,從 ZK 中拿到對應 topic 的 partition 資訊和 partition 的 Leader 的相關資訊連線到對應 Leader 對應的 brokerconsumer 將自己儲存的 offset 傳送給 LeaderLeader 根據 offset 等資訊定位到 segment(索引檔案和日誌檔案)根據索引檔案中的內容,定位到日誌檔案中該偏移量對應的開始位置讀取相應長度的資料並返回給 consumer 。

8、kafka 重啟是否會導致資料丟失?

kafka 是將資料寫到磁碟的,一般資料不會丟失。但是在重啟 kafka 過程中,如果有消費者消費訊息,那麼 kafka 如果來不及提交 offset,可能會造成資料的不準確(丟失或者重複消費)。

9、kafka 宕機瞭如何解決?

  • 先考慮業務是否受到影響:

kafka 宕機了,首先我們考慮的問題應該是所提供的服務是否因為宕機的機器而受到影響,如果服務提供沒問題,如果實現做好了叢集的容災機制,那麼這塊就不用擔心了。

  • 節點排錯與恢復

想要恢復叢集的節點,主要的步驟就是通過日誌分析來檢視節點宕機的原因,從而解決,重新恢復節點 。

10、為什麼 Kafka 不支援讀寫分離?

在 Kafka 中,生產者寫入訊息、消費者讀取訊息的操作都是與 leader 副本進行互動的,從 而實現的是一種主寫主讀的生產消費模型。

Kafka 並不支援主寫從讀,因為主寫從讀有 2 個很明顯的缺點 :

  1. 資料一致性問題:

資料從主節點轉到從節點必然會有一個延時的時間視窗,這個時間視窗會導致主從節點之間的資料不一致。某一時刻,在主節點和從節點中 A 資料的值都為 X, 之後將主節點中 A 的值修改為 Y,那麼在這個變更通知到從節點之前,應用讀取從節點中的 A 資料的值並不為最新的 Y,由此便產生了資料不一致的問題 。

  1. 延時問題:

類似 Redis 這種元件,資料從寫入主節點到同步至從節點中的過程需要經歷 網路→主節點記憶體→網路→從節點記憶體 這幾個階段,整個過程會耗費一定的時間。而在 Kafka 中,主從同步會比 Redis 更加耗時,它需要經歷 網路→主節點記憶體→主節點磁碟→網路→從節點記憶體→從節點磁碟 這幾個階段 。對延時敏感的應用而言,主寫從讀的功能並不太適用 。

而 kafka 的主寫主讀的優點就很多了:

可以簡化程式碼的實現邏輯,減少出錯的可能; 將負載粒度細化均攤,與主寫從讀相比, 不僅負載效能更好,而且對使用者可控 ; 沒有延時的影響 ; 在副本穩定的情況下,不會出現資料不一致的情況 。

11、Kafka 訊息資料積壓,Kafka 消費能力不足怎麼處理?

如果是 Kafka 消費能力不足,則可以考慮增加 Topic 的分割槽數,並且同時提升消費組的消費者數量,消費者數=分割槽數。(兩者缺一不可)

如果是下游的資料處理不及時: 提高每批次拉取的數量。批次拉取資料過少(拉取資料/處理時間<生產速度),使處理的資料小於生產的資料,也會造成資料積壓 。

12、Kafka 單條日誌傳輸大小

kafka 對於訊息體的大小預設為單條最大值是 1M 但是在我們應用場景中, 常常會出現一條訊息大於 1M,如果不對 kafka 進行配置。則會出現生產者無法將訊息推送到 kafka 或消費者無法去消費 kafka 裡面的資料, 這時我們就要對 kafka 進行以下配置:

server.properties

1replica.fetch.max.bytes: 1048576 broker 可複製的訊息的最大位元組數, 預設為 1M 2message.max.bytes: 1000012 kafka 會接收單個訊息 size 的最大限制, 預設為1M 左右

複製程式碼

注意:message.max.bytes 必須小於等於 replica.fetch.max.bytes,否則就會導致 replica 之間資料同步失敗

13、kafka 內部如何保證順序,結合外部元件如何保證消費者的順序?

kafka 只能保證 partition 內是有序的,但是 partition 間的有序是沒辦法的。我們常用的做法,是從業務上把需要有序的打到同一個 partition 。