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

- 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內部是有序的
偏移量

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”檔案

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

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


副本

-
每一個分割槽都存在一個ISR(in-sync replicas)
-
ISR集合中的每一個副本都與leader保持同步狀態,不在裡面的保持不了同步狀態
-
只有ISR中的副本才有資格被選為leader
-
Producer寫入的訊息只有被ISR中的副本都接收到,才被視為"已提交"
-
Log End Offset:Producer 寫入到 Kafka 中的最新一條資料的 offset
-
High Watermark:已經成功備份到其他 replicas 中的最新一條資料的 offset,也就是說 Log End Offset 與 High Watermark 之間的資料已經寫入到該 partition 的 leader 中,但是還未成功備份到其他的 replicas 中
副本同步流程:

Controller
Controller類似於叢集的master,主要管理如下幾塊:
- Broker 的上線、下線處理
- topic 的分割槽擴容,處理分割槽副本的分配、leader 選舉
Controller通過broker搶佔zk臨時節點選舉出來,且controller與所有broker建立長連線
Controller管理partition leader選舉,主要有以下幾種方式:
選舉方式 | 說明 |
---|---|
OfflinePartitionLeaderSelector | leader 掉線時觸發 |
ReassignedPartitionLeaderSelector | 分割槽的副本重新分配資料同步完成後觸發的 |
PreferredReplicaPartitionLeaderSelector | 最優 leader 選舉,手動觸發或自動 leader 均衡排程時觸發 |
ControlledShutdownLeaderSelector | broker 傳送 ShutDown 請求主動關閉服務時觸發 |
訊息冪等
問題:

- 在 0.11.0 之前,producer保證at least once
- at least once可能帶來重複資料 網路請求延遲等導致的重試操作,在傳送請求重試時 Server 端並不知道這條請求是否已經處理(沒有記錄之前的狀態資訊),所以就會有可能導致資料請求的重複傳送,這是 Kafka 自身的機制(異常時請求重試機制)導致的資料重複
解決方案:
- PID(Producer ID),用來標識每個 producer client
- sequence numbers,client 傳送的每條訊息都會帶相應的 sequence number,Server 端就是根據這個值來判斷資料是否重複
Rebalance
kafka rebalance發生的5種情況:
- 有新的消費者加入Consumer Group。
- 有消費者當機下線。消費者並不一定需要真正下線,例如遇到長時間的GC、網路延遲導致消費者長時間未向GroupCoordinator傳送HeartbeatRequest時,GroupCoordinator會認為消費者下線。
- 有消費者主動退出Consumer Group。
- Consumer Group訂閱的任一Topic出現分割槽數量的變化。
- 消費者呼叫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:
- Consumer首先向GroupCoordinator傳送JoinGroupRequest請求,其中包含消費者的相關資訊
- GroupCoordinator從中選取一個消費者成為Group Leader,封裝成JoinGroupResponse返回給每個消費者
- 只有Group Leader收到的JoinGroupResponse中封裝了所有消費者的資訊, Group Leader根據消費者的資訊以及選定的分割槽分配策略進行分割槽分配。
Sync Group:
- 每個消費者會傳送SyncGroupRequest到GroupCoordinator,但是隻有Group Leader的SyncGroupRequest請求包含了分割槽的分配結果
- GroupCoordinator根據Group Leader的分割槽分配結果,形成SyncGroupResponse返回給所有Consumer
- 消費者收到SyncGroupResponse後進行解析,即可獲取分配給自身的partition