當前位置: 華文世界 > 科技

全面總結Kafka基礎

2024-09-06科技

前言

Kafka 的基礎知識點還是蠻多的,本文針對 Kafka 的一些面試過程中常見的基礎知識進行全面總結,方便大家進行查漏補缺。

正文

一. Broker概念

Kafka 中,一個 Kafka 伺服端的例項,就叫做一個 Broker 。已知 Kafka 使用 Zookeeper 來維護 Kafka 集群資訊,如下圖所示。

Kafka-Zookeeper儲存資訊腦圖

Broker 啟動時,會在 Zookeeper /brokers/ids 路徑上建立臨時節點,將自己的 id 註冊到 Zookeeper

Kafka 元件會訂閱 Zookeeper /brokers/ids 路徑,當有 Broker 加入或者結束集群時,這些 Kafka 元件就能夠獲得通知。

二. Topic概念

可以在 Broker 上建立 Topic ,生產者向 Topic 發送訊息,消費者訂閱 Topic 並從 Topic 拉取訊息。可以用下圖進行示意。

Kafka-Topic示意圖

三. Partition概念

一個 Topic 可以有多個分區,這裏的分區就叫做 Partition ,分區的作用是提高 Kafka 的吞吐量。

分區可以用下圖進行示意。

Kafka-Partition示意圖

可以用下面的指令在建立 Topic 的時候指定分區,指令如下所示。

./kafka-topics.sh --bootstrap-server 127.0.0.1:9092,127.0.0.1:9093,127.0.0.1:9094 --replication-factor 3 --partitions 3 --create --topic mytopic-0

上述指令會建立一個分區數為 3 ,副本數為 3 Topic

一個分區可以有多個副本,且一個分區的多個副本不能在同一個 Broker 上,例如只有 3 Broker ,但是建立 Topic 的時候,指定副本數為 4 ,此時建立 Topic 會失敗。

分區的多個副本可以分為 leader 節點和 follower 節點,且 leader 節點為客戶端提供 讀寫 功能, follower 節點會從 leader 節點同步數據但不提供讀寫功能,這樣能避免出現讀寫不一致的問題。

建立 Topic 時,會在 Broker 上為這個 Topic 的分區建立目錄,如下所示。

Topic分區目錄建立圖

分區目錄的內容如下所示。

Topic分區目錄內容圖

每個檔含義如下。

  1. index 檔是索引檔 。記錄訊息的編號;
  2. timeindex 檔是時間戳索引 。記錄生產者發送訊息的時間和訊息記錄到日誌檔的時間;
  3. log 是日誌檔 。記錄訊息。

因為 log 檔會越來越大,此時根據 index 檔進行檢索會影響效率,所以還需要對上述檔進行切分,切分出來的單位叫做 Segment ),可以透過 log.segment.bytes 來控制一段檔的大小。 Segment 的示意如下。

00000000000000000000.index00000000000000000000.log00000000000000000000.timeindex00000000000000050000.index00000000000000050000.log00000000000000050000.timeindex

四.消費者組

消費者組是 Kafka 提供的可延伸且具有容錯性的消費者機制。一個消費者組記憶體在多個消費者,這些消費者共享一個 Group ID 。消費者組示意如下。

Kafka-消費者組示意圖

關於消費者組,有如下說明。

  1. 消費者組的不同消費者不能同時消費同一個 Partition
  2. 如果消費者組裏消費者數量和 Partition 數量一樣則一個消費者消費一個 Partition
  3. 如果消費者組裏消費者數量大於 Partition 數量則部份消費者會無法消費到 Partition
  4. 如果消費者組裏消費者數量小於 Partition 數量則部份消費者會消費多個 Partition

五.偏移量

偏移量,即 Consumer Offset ,用於儲存消費者對 Partition 消費的位移量。

偏移量儲存在 Kafka 的內部 Topic 中,這個內部 Topic 叫做_ consumer_offsets ,該 Topic 預設有 50 個分區,將消費者的 Group ID 進行 hash 後再對 50 取模,得到的結果對應的分區就會用於儲存這個消費者的偏移量。

_ consumer_offsets 的每條訊息格式示意圖如下所示。

Kafka-消費者偏移量訊息結構圖

註意_ consumer_offsets 是儲存在 Broker 上的。

六.生產者發送訊息完整流程

生產者發送訊息完整流程圖如下所示。

Kafka-生產者發送訊息流程圖

結合上述流程圖,對訊息發送流程說明如下。

  1. 生產者生成訊息 Record
  2. Record 經過攔截器鏈;
  3. key value 進行序列化;
  4. 使用自訂或者預設的分區器獲取 Record 所屬分區 Partition
  5. Record 放入訊息累加器 RecordAccumulator 。根據 Topic Partition ,可以確定一個雙端佇列 Deque ,該佇列每個節點為多條 Record 的合集即 ProducerBatch ,新 Record 會被添加到佇列最後一個節點上;
  6. Sender 將相同 Broker 節點的可發送 ProducerBatch 合並到一個 Request 中並行送。 Sender 會持續掃描 RecordAccumulator 中的 ProducerBatch ,只要滿足大小為 batch.size 預設 16K )或者最早 Record 等待已經超過 linger.ms ,該 ProducerBatch 就會被 Sender 收集,然後 Sender 會合並收集的相同 Broker ProducerBatch 到一個 Request 中並行送;
  7. 緩存請求 Request inFlightRequest 緩沖區中。 inFlightRequest 中為每個 Broker 分配了一個佇列,新 Request 會添加到佇列頭,每個佇列最多容納的 Request 個數由 max.in.flight.requests.per.connection 預設為 5 )控制,佇列滿後不會生成新 Request
  8. Selector 發送請求到 Broker
  9. Broker 收到並處理 Request 後,對 Request 進行 ACK
  10. 客戶端收到 Request ACK 後,將 Request inFlightRequest 中移除。

七.分區策略

Kafka 中訊息的分區計算策略小結如下。

  1. 訊息中指定了分區 。此時使用指定的分區;
  2. 訊息中未指定分區但有自訂分區器 。此時使用自訂分區器計算分區;
  3. 訊息中未指定分區也沒有自訂分區器但訊息鍵不為空 。此時對鍵求哈希值,並用求得的哈希值對 Topic 的分區數取模得到分區;
  4. 如果前面都不滿足 。此時根據 Topic 取一個遞增整數並對 Topic 分區數求模得到分區。

八. ISR機制

當生產者向伺服端發送訊息後,通常需要等待伺服端的 ACK ,這一過程可以用下圖進行示意。

Kafka-伺服端響應Producer示意圖

Producer 會將訊息發送給 Topic 對應分區的 leader 節點,然後 leader follower 進行同步,如果全部正常的 follower 同步成功( follower 完成訊息落盤 ),那麽伺服端就可以向 Producer 發送 ACK

上面描述中的正常 follower 的集合,叫做 ISR In-Sync Replica Set ),只有與 leader 節點正常通訊的 follower 才會被放入 ISR 中,換言之,只有 ISR 中的 follower 才有資格讓 leader 等待同步結果。

如果 leader 掛掉,那麽會在 ISR 中選擇新的 leader

九. ACK機制

Producer 發送訊息的時候,可以透過 acks 配置項來決定伺服端返回 ACK 的策略,如下所示。

  1. acks 設定為 0 Producer 不需要等待伺服端返回 ACK ,即 Producer 不關心伺服端是否成功將訊息落盤;
  2. acks 設定為 1 leader 成功將訊息落盤便返回 ACK ,這是預設策略;
  3. acks 設定為 -1 leader ISR 中全部 follower 落盤成功才返回 ACK

十. Segment生成策略

分區在磁盤上由多個 Segment 組成,如下所示。

Topic分區目錄內容圖

有如下參數控制 Segment 的生成策略。

  1. log.segment.bytes 。用於設定單個 Segment 大小,當某個 Segment 的大小超過這個值後,就需要生成新的 Segment
  2. log.roll.hours 。用於設定每隔多少小時就生成新的 Segment
  3. log.index.size.max.bytes 。當 Segment index 檔達到這個大小時,也需要生成新的 Segment

十一. index檔

使用 Kafka 提供的 kafka-dump-log.sh 工具,可以開啟 index 檔,開啟後的 index 檔可以表示如下。

offset: 613 position: 5252offset: 1284 position: 10986offset: 1803 position: 17491offset: 2398 position: 25792offset: 3422 position: 35309offset: 4446 position: 51690offset: 5470 position: 68071offset: 6494 position: 84452offset: 7518 position: 100833

上述範例中, offset 是偏移量, position 表示這個 offset 對應的訊息在 log 檔裏的位置。

index 檔建立的索引是稀疏索引,示意圖如下。

Kafka-稀疏索引範例圖

十二. timeindex檔

每一條被發送的訊息都會記錄時間戳,這裏的時間戳可以是發送訊息時間戳,或者是訊息落盤時間戳。可以配置如下。

  1. log.message.timestamp.type 設定為 createtime 。表示發送訊息時間戳;
  2. log.message.timestamp.type 設定為 logappendtime 。表示訊息落盤時間戳。

十三.索引檢索過程

  1. 根據 offset 找到在哪個 Segment 中;
  2. Segment index 檔根據 offset 找到訊息的 position
  3. 根據 position Segment log 檔中最終找到訊息。

十四. Partition儲存總結

Partition 儲存示意圖如下。

Kafka-Partition儲存示意圖

十五. Kafka中的Controller選舉

Controller Kafka 集群中負責對整個集群進行協調管理,比如完成 分區分配 Leader 選舉 副本管理 等。

關於 Controller 的選舉,有如下註意點。

  1. 啟動時選舉 。集群中 Broker 啟動時會去 Zookeeper 建立臨時節點 /controller ,最先建立成功的 Broker 會成為 Controller
  2. Controller 異常時選舉 。如果 Controller 掛掉,此時其它 Broker 會透過 Watch 物件收到 Controller 變更的訊息,然後就會嘗試去 Zookeeper 建立臨時節點 /controller ,只會有一個 Broker 建立成功,建立失敗的 Broker 會再次建立 Watch 物件來監視新 Controller
  3. Borker 異常 。如果集群中某個非 Controller Broker 掛掉,此時 Controller 會檢查掛掉的 Broker 上是否有某個分區的 leader 副本,如果有,則需要為這個分區選舉新的 leader 副本,並更新分區的 ISR 集合;
  4. Broker 加入 。如果有一個 Broker 加入集群,則 Controller 會去判斷新加入的 Broker 中是否含有當前已有分區的副本,如果有,那麽需要去從 leader 副本中同步數據。

十六.分區leader副本選舉

一個分區有三種集合,如下所示。

  1. AR Assigned Replicas )。分區中的所有副本;
  2. ISR In-Sync Replicas )。與 leader 副本保持一定同步程度的副本, ISR 包括 leader 副本自身;
  3. OSR Out-of-Sync Replicas )。與 leader 副本同步程度滯後過多的副本。

上述三種集合的關系是 AR = ISR + OSR

分區 leader 副本選舉有如下註意點。

  1. leader 副本會維護和跟蹤 ISR 中所有副本與 leader 副本的同步程度,如果某個副本的同步程度滯後過多,則 leader 副本會將這個副本從 ISR 中移到 OSR 中;
  2. OSR 中有副本重新與 leader 副本保持一定同步程度,則 leader 副本會將其從 OSR 中移到 ISR
  3. leader 副本發生故障時, Controller 會負責為這個分區從 ISR 中選舉新的 leader 副本。

十七.主從同步

分區的 leader follower 之間的主從同步示意圖如下。

Kafka-主從同步示意圖

有兩個重要概念如下所示。

  1. LEO Log End Offset )。下一條待寫入訊息的 Offset
  2. HW High Watermark )。 ISR 集合中的最小 LEO

那麽對於上圖而言, HW 6 ,那麽消費者最多只能消費到 HW 之前的訊息,也就是 Offset 5 的訊息。

主從同步規則如下。

  1. follower 會向 leader 發送 fetch 請求,然後 leader follower 發送數據;
  2. follower 接收到數據後,依次寫入訊息並且更新 LEO
  3. leader 最後會更新 HW

leader follower 發生故障時,處理策略如下。

  1. 如果 follower 掛掉,那麽當 follower 恢復後,需要先將 HW HW 之後的數據丟棄,然後再向 leader 發起同步;
  2. 如果 leader 掛掉,則會先從 follower 中選擇一個成為 leader ,然後其它 follower HW HW 之後的數據丟棄,然後再向 leader 發起同步。

十八. Kafka為什麽快

  1. 順序讀寫
  2. 索引
  3. 批次讀寫和檔壓縮
  4. 零拷貝

十九.零拷貝

如果要將磁盤中的檔內容,發送到遠端伺服器,則整個數據流轉如下所示。

Kafka-傳統IO示意圖

步驟說明如下。

  1. 從磁盤檔讀取檔內容,並拷貝到內核緩沖區;
  2. CPU 控制器將內核緩沖區的數據拷貝到使用者緩沖區;
  3. 應用程式中呼叫 write() 方法,將使用者緩沖區的數據拷貝到 Socket 緩沖區;
  4. Socket 緩沖區的數據拷貝到網卡。

一共經歷了四次拷貝( 和四次 CPU 上下文切換 ),其中如下兩次拷貝是多余的。

  1. 內核緩沖區拷貝到使用者緩沖區;
  2. 使用者緩沖區拷貝到 Socket 緩沖區。

Kafka 中的零拷貝,就是將上述兩次多余的拷貝省掉,示意圖如下。

Kafka-零拷貝示意圖

零拷貝步驟如下所示。

  1. 從磁盤檔讀取檔內容,並拷貝到內核緩沖區;
  2. 將檔描述符和數據長度載入到 Socket 緩沖區;
  3. 將數據直接從內核緩沖區拷貝到網卡。

一共只會經歷兩次拷貝( 和兩次 CPU 上下文切換 )。

總結不易,如果本文對你有幫助,煩請點贊,收藏加關註,謝謝帥氣漂亮的你。

你的名字-002

作者:半夏之沫

原文:https://juejin.cn/post/7391034124374261775