kafka原理解析

吻劍發表於2019-05-08

kafka是大家比較常用的訊息中介軟體,本文主要介紹kafka基本元件及其相關原理

基本架構

image.png

  • Broker:訊息中介軟體處理節點,一個Kafka節點就是一個broker,一個或者多個Broker可以組成一個Kafka叢集
  • Topic:Kafka根據topic對訊息進行歸類,釋出到Kafka叢集的每條訊息都需要指定一個topic
  • Producer:訊息生產者,向Broker傳送訊息的客戶端
  • Consumer:訊息消費者,從Broker讀取訊息的客戶端
  • ConsumerGroup:每個Consumer屬於一個特定的Consumer Group,一條訊息可以傳送到多個不同的Consumer Group,但是一個Consumer Group中只能有一個Consumer能夠消費該訊息
  • Partition:物理上的概念,一個topic可以分為多個partition,每個partition內部是有序的

偏移量

image.png

Kafka通過offset保證訊息在分割槽內的順序,offset的順序性不跨分割槽 Kafka0.10以後,使用一個專門的topic __consumer_offset儲存offset __consumer_offset日誌留存方式為compact,也就是說,該topic會對key相同的訊息進行整理

__consumer_offset內儲存三類訊息:

  • Consumer group組後設資料訊息
  • Consumer group位移訊息
  • Tombstone訊息

kafka log

儲存

每個Partition其實都會對應一個日誌目錄:{topicName}-{partitionid}/,在目錄下面會對應多個日誌分段(LogSegment)。LogSegment檔案由兩部分組成,分別為“.index”檔案和“.log”檔案

image.png
索引檔案使用稀疏索引的方式,避免對日誌每條資料建索引,節省儲存空間

傳送

使用page cache順序讀檔案,作業系統可以預讀資料到 page cache 使用mmap直接將日誌檔案對映到虛擬地址空間

image.png
read()是系統呼叫,首先將檔案從硬碟拷貝到核心空間的一個緩衝區,再將這些資料拷貝到使用者空間,實際上進行了兩次資料拷貝; mmap()也是系統呼叫,但沒有進行資料拷貝,當缺頁中斷髮生時,直接將檔案從硬碟拷貝到使用者空間,只進行了一次資料拷貝。 Java中使用MappedByteBuffer封裝了mmap

零拷貝:訊息資料直接從 page cache 傳送到網路 通常的檔案讀取需要經歷下圖的流程,有兩次使用者態與核心態之間記憶體的拷貝

image.png
kafka使用零拷貝,避免訊息在核心態和使用者態間的來回拷貝
image.png

副本

image.png

  • 每一個分割槽都存在一個ISR(in-sync replicas)

  • ISR集合中的每一個副本都與leader保持同步狀態,不在裡面的保持不了同步狀態

  • 只有ISR中的副本才有資格被選為leader

  • Producer寫入的訊息只有被ISR中的副本都接收到,才被視為"已提交"

    image.png

  • Log End Offset:Producer 寫入到 Kafka 中的最新一條資料的 offset

  • High Watermark:已經成功備份到其他 replicas 中的最新一條資料的 offset,也就是說 Log End Offset 與 High Watermark 之間的資料已經寫入到該 partition 的 leader 中,但是還未成功備份到其他的 replicas 中

副本同步流程:

image.png

Controller

Controller類似於叢集的master,主要管理如下幾塊:

  • Broker 的上線、下線處理
  • topic 的分割槽擴容,處理分割槽副本的分配、leader 選舉

Controller通過broker搶佔zk臨時節點選舉出來,且controller與所有broker建立長連線

Controller管理partition leader選舉,主要有以下幾種方式:

選舉方式 說明
OfflinePartitionLeaderSelector leader 掉線時觸發
ReassignedPartitionLeaderSelector 分割槽的副本重新分配資料同步完成後觸發的
PreferredReplicaPartitionLeaderSelector 最優 leader 選舉,手動觸發或自動 leader 均衡排程時觸發
ControlledShutdownLeaderSelector broker 傳送 ShutDown 請求主動關閉服務時觸發

訊息冪等

問題:

image.png

  • 在 0.11.0 之前,producer保證at least once
  • at least once可能帶來重複資料 網路請求延遲等導致的重試操作,在傳送請求重試時 Server 端並不知道這條請求是否已經處理(沒有記錄之前的狀態資訊),所以就會有可能導致資料請求的重複傳送,這是 Kafka 自身的機制(異常時請求重試機制)導致的資料重複

解決方案:

  • PID(Producer ID),用來標識每個 producer client
  • sequence numbers,client 傳送的每條訊息都會帶相應的 sequence number,Server 端就是根據這個值來判斷資料是否重複
    image.png

Rebalance

kafka rebalance發生的5種情況:

  1. 有新的消費者加入Consumer Group。
  2. 有消費者當機下線。消費者並不一定需要真正下線,例如遇到長時間的GC、網路延遲導致消費者長時間未向GroupCoordinator傳送HeartbeatRequest時,GroupCoordinator會認為消費者下線。
  3. 有消費者主動退出Consumer Group。
  4. Consumer Group訂閱的任一Topic出現分割槽數量的變化。
  5. 消費者呼叫unsubscrible()取消對某Topic的訂閱。

kafka通過GroupCoordinator管理rebalance操作

  • GroupCoordinator是KafkaServer中用於管理Consumer Group的元件
  • GroupCoordinator在ZooKeeper上新增Watcher
  • 獲取GroupCoordinator:消費者會向Kafka叢集中的任一Broker傳送ConsumerMetadataRequest
  • 消費者連線到GroupCoordinator並週期性地傳送HeartbeatRequest
  • 如果HeartbeatResponse中帶有IllegalGeneration異常,說明GroupCoordinator發起了Rebalance操作,此時進入rebalance環節 Rebalance分為兩個流程。

Join Group:

  1. Consumer首先向GroupCoordinator傳送JoinGroupRequest請求,其中包含消費者的相關資訊
  2. GroupCoordinator從中選取一個消費者成為Group Leader,封裝成JoinGroupResponse返回給每個消費者
  3. 只有Group Leader收到的JoinGroupResponse中封裝了所有消費者的資訊, Group Leader根據消費者的資訊以及選定的分割槽分配策略進行分割槽分配。

Sync Group:

  • 每個消費者會傳送SyncGroupRequest到GroupCoordinator,但是隻有Group Leader的SyncGroupRequest請求包含了分割槽的分配結果
  • GroupCoordinator根據Group Leader的分割槽分配結果,形成SyncGroupResponse返回給所有Consumer
  • 消費者收到SyncGroupResponse後進行解析,即可獲取分配給自身的partition

相關文章