Kafka 概述:深刻理解架構

本文主要講解 Kafka 是什麼、Kafka 的架構包括工做流程和存儲機制,以及生產者和消費者,最終你們會掌握 Kafka 中最重要的概念,分別是 broker、producer、consumer、consumer group、topic、partition、replica、leader、follower,這是學會和理解 Kafka 的基礎和必備內容。面試

1. 定義

Kafka 是一個分佈式的基於發佈/訂閱模式消息隊列(Message Queue),主要應用與大數據實時處理領域。算法

1.1 消息隊列

Kafka 本質上是一個 MQ(Message Queue),使用消息隊列的好處? (面試會問)緩存

  1. 解耦:容許咱們獨立的擴展或修改隊列兩邊的處理過程。
  2. 可恢復性:即便一個處理消息的進程掛掉,加入隊列中的消息仍然能夠在系統恢復後被處理。
  3. 緩衝:有助於解決生產消息和消費消息的處理速度不一致的狀況。
  4. 靈活性&峯值處理能力:不會由於突發的超負荷的請求而徹底崩潰,消息隊列可以使關鍵組件頂住突發的訪問壓力。
  5. 異步通訊:消息隊列容許用戶把消息放入隊列但不當即處理它。

1.2 發佈/訂閱模式


一對多,生產者將消息發佈到 topic 中,有多個消費者訂閱該主題,發佈到 topic 的消息會被全部訂閱者消費,被消費的數據不會當即從 topic 清除。

2. 架構


Kafka 存儲的消息來自任意多被稱爲 Producer 生產者的進程。數據從而能夠被髮布到不一樣的 Topic 主題下的不一樣 Partition 分區。在一個分區內,這些消息被索引並連同時間戳存儲在一塊兒。其它被稱爲 Consumer 消費者的進程能夠從分區訂閱消息。Kafka 運行在一個由一臺或多臺服務器組成的集羣上,而且分區能夠跨集羣結點分佈。
下面給出 Kafka 一些重要概念,讓你們對 Kafka 有個總體的認識和感知,後面還會詳細的解析每個概念的做用以及更深刻的原理。

  • Producer: 消息生產者,向 Kafka Broker 發消息的客戶端。
  • Consumer: 消息消費者,從 Kafka Broker 取消息的客戶端。
  • Consumer Group: 消費者組(CG),消費者組內每一個消費者負責消費不一樣分區的數據,提升消費能力。一個分區只能由組內一個消費者消費,消費者組之間互不影響。全部的消費者都屬於某個消費者組,即消費者組是邏輯上的一個訂閱者。
  • Broker: 一臺 Kafka 機器就是一個 broker。一個集羣由多個 broker 組成。一個 broker 能夠容納多個 topic。
  • Topic: 能夠理解爲一個隊列,topic 將消息分類,生產者和消費者面向的是同一個 topic。
  • Partition: 爲了實現擴展性,提升併發能力,一個很是大的 topic 能夠分佈到多個 broker (即服務器)上,一個 topic 能夠分爲多個 partition,每一個 partition 是一個 有序的隊列。
  • Replica: 副本,爲實現備份的功能,保證集羣中的某個節點發生故障時,該節點上的 partition 數據不丟失,且 Kafka 仍然可以繼續工做,Kafka 提供了副本機制,一個 topic 的每一個分區都有若干個副本,一個 leader 和若干個 follower。
  • Leader: 每一個分區多個副本的「主」副本,生產者發送數據的對象,以及消費者消費數據的對象,都是 leader。
  • Follower: 每一個分區多個副本的「從」副本,實時從 leader 中同步數據,保持和 leader 數據的同步。leader 發生故障時,某個 follower 還會成爲新的 leader。
  • offset: 消費者消費的位置信息,監控數據消費到什麼位置,當消費者掛掉再從新恢復的時候,能夠從消費位置繼續消費。
  • Zookeeper: Kafka 集羣可以正常工做,須要依賴於 zookeeper,zookeeper 幫助 Kafka 存儲和管理集羣信息。

3 工做流程

Kafka集羣將 Record 流存儲在稱爲 topic 的類別中,每一個記錄由一個鍵、一個值和一個時間戳組成。Kafka 是一個分佈式流平臺,這究竟是什麼意思?服務器

  • 發佈和訂閱記錄流,相似於消息隊列或企業消息傳遞系統。
  • 以容錯的持久方式存儲記錄流。
  • 處理記錄流。

Kafka 工做流程

Kafka 中消息是以 topic 進行分類的,生產者生產消息,消費者消費消息,面向的都是同一個 topic。
topic 是邏輯上的概念,而 partition 是物理上的概念,每一個 partition 對應於一個 log 文件,該 log 文件中存儲的就是 Producer 生產的數據。Producer 生產的數據會不斷追加到該 log 文件末端,且每條數據都有本身的 offset。消費者組中的每一個消費者,都會實時記錄本身消費到了哪一個 offset,以便出錯恢復時,從上次的位置繼續消費。

4 存儲機制

Kafka文件存儲機制

因爲生產者生產的消息會不斷追加到 log 文件末尾,爲防止 log 文件過大致使數據定位效率低下,Kafka 採起了 分片索引機制,將每一個 partition 分爲多個 segment,每一個 segment 對應兩個文件:「.index」 索引文件和 「.log」 數據文件。這些文件位於同一文件下,該文件夾的命名規則爲:topic 名-分區號。例如,first 這個 topic 有三分分區,則其對應的文件夾爲 first-0,first-1,first-2。

# ls /root/data/kafka/first-0        
00000000000000009014.index    
00000000000000009014.log
00000000000000009014.timeindex
00000000000000009014.snapshot   
leader-epoch-checkpoint
複製代碼

index 和 log 文件以當前 segment 的第一條消息的 offset 命名。下圖爲 index 文件 和 log 文件的結構示意圖。
網絡


「.index」 文件存儲大量的索引信息,「.log」 文件存儲大量的數據,索引文件中的元數據指向對應數據文件中 message 的物理偏移量。

5. 生產者

5.1 分區策略

5.1.1 分區緣由

  • 方便在集羣中擴展,每一個 partition 能夠經過調整以適應它所在的機器,而一個 topic 又能夠有多個 partition 組成,所以能夠以 partition 爲單位讀寫了。
  • 能夠提升併發,所以能夠以 partition 爲單位讀寫了。

5.1.2 分區原則

咱們須要將 Producer 發送的數據封裝成一個 ProducerRecord 對象。該對象須要指定一些參數:架構

  • topic:string 類型,NotNull
  • partition:int 類型,可選
  • timestamp:long 類型,可選
  • key:string類型,可選
  • value:string 類型,可選
  • headers:array 類型,Nullable

(1) 指明 partition 的狀況下,直接將給定的 value 做爲 partition 的值。
(2) 沒有指明 partition 但有 key 的狀況下,將 key 的 hash 值與分區數取餘獲得 partition 值。
(3) 既沒有 partition 有沒有 key 的狀況下,第一次調用時隨機生成一個整數(後面每次調用都在這個整數上自增),將這個值與可用的分區數取餘,獲得 partition 值,也就是常說的 round-robin 輪詢算法。併發

5.2 數據可靠性保證

爲保證 producer 發送的數據,能可靠地發送到指定的 topic,topic 的每一個 partition 收到 producer 發送的數據後,都須要向 producer 發送 ack(acknowledge 確認收到),若是 producer 收到 ack,就會進行下一輪的發送,不然從新發送數據。
dom

5.2.1 副本數據同步策略

(1)什麼時候發送 ack?
確保有 follower 與 leader 同步完成,leader 再發送 ack,這樣才能保證 leader 掛掉以後,能在 follower 中選舉出新的 leader 而不丟數據。
(2)多少個 follower 同步完成後發送 ack?
所有 follower 同步完成,再發送 ack。
異步

同步策略方案比較

5.2.2 ISR

採用第二種方案,全部 follower 完成同步,producer 才能繼續發送數據,設想有一個 follower 由於某種緣由出現故障,那 leader 就要一直等到它完成同步。這個問題怎麼解決?
leader維護了一個動態的 in-sync replica set(ISR):和 leader 保持同步的 follower 集合。當 ISR 集合中的 follower 完成數據的同步以後,leader 就會給 follower 發送 ack。若是 follower 長時間未向 leader 同步數據,則該 follower 將被踢出 ISR 集合,該時間閾值由 replica.lag.time.max.ms 參數設定。leader 發生故障後,就會從 ISR 中選舉出新的 leader。分佈式

5.2.3 ack 應答機制

對於某些不過重要的數據,對數據的可靠性要求不是很高,可以容忍數據的少許丟失,因此不必等 ISR 中的 follower 所有接受成功。
因此 Kafka 爲用戶提供了三種可靠性級別,用戶根據可靠性和延遲的要求進行權衡,選擇如下的配置。
(1)ack 參數配置:

  • 0:producer 不等待 broker 的 ack,這提供了最低延遲,broker 一收到數據尚未寫入磁盤就已經返回,當 broker 故障時有可能丟失數據。
  • 1:producer 等待 broker 的 ack,partition 的 leader 落盤成功後返回 ack,若是在 follower 同步成功以前 leader 故障,那麼將會丟失數據。
  • -1(all):producer 等待 broker 的 ack,partition 的 leader 和 follower 所有落盤成功後才返回 ack。可是在 broker 發送 ack 時,leader 發生故障,則會形成數據重複。

acks=-1 形成數據重複分析

5.2.4 故障處理細節

Log 文件中的 HW 和 LEO

LEO:每一個副本最大的 offset。
HW:消費者能見到的最大的 offset,ISR 隊列中最小的 LEO。

(1)Follower 故障
follower 發生故障後會被臨時踢出 ISR 集合,待該 follower 恢復後,follower 會 讀取本地磁盤記錄的上次的 HW,並將 log 文件高於 HW 的部分截取掉,從 HW 開始向 leader 進行同步數據操做。等該 follower 的 LEO 大於等於該 partition 的 HW,即 follower 追上 leader 後,就能夠從新加入 ISR 了。
(2)Leader 故障
leader 發生故障後,會從 ISR 中選出一個新的 leader,以後,爲保證多個副本之間的數據一致性,其他的 follower 會先將各自的 log 文件高於 HW 的部分截掉,而後重新的 leader 同步數據。
注意:這隻能保證副本之間的數據一致性,並不能保證數據不丟失或者不重複。

5.3 Exactly Once 語義

將服務器的 ACK 級別設置爲-1,能夠保證 producer 到 server 之間不會丟失數據,即 At Least Once 語義。相對的,將服務器 ACK 級別設置爲0,能夠保證生產者每條消息只會被髮送一次,即At Most Once 語義。
At Least Once 能夠保證數據不丟失,可是不能保證數據不重複;相對的,At Most Once 能夠保證數據不重複,可是不能保證數據不丟失。可是,對於一些很是重要的信息,好比交易數據,下游數據消費者要求數據既不重複也不丟失,即 Exactly Once 語義。
0.11版本的 Kafka,引入了冪等性:producer 不論向 server 發送多少重複數據,server 端都只會持久化一條。即:

At Least Once + 冪等性 = Exactly Once   
複製代碼

要啓用冪等性,只須要將 producer 的參數中 enable.idompotence 設置爲 true 便可。開啓冪等性的 producer 在初始化時會被分配一個 PID,發往同一 partition 的消息會附帶 Sequence Number。而 borker 端會對 <PID,Partition,SeqNumber> 作緩存,當具備相同主鍵的消息提交時,broker 只會持久化一條。
可是 PID 重啓後就會變化,同時不一樣的 partition 也具備不一樣主鍵,因此冪等性沒法保證跨分區會話的 Exactly Once。

6. 消費者

6.1 消費方式

consumer 採用 pull(拉取)模式從 broker 中讀取數據。
consumer 採用 push(推送)模式,broker 給 consumer 推送消息的速率是由 broker 決定的,很難適應消費速率不一樣的消費者。它的目標是儘量以最快速度傳遞消息,可是這樣很容易形成 consumer 來不及處理消息,典型的表現就是拒絕服務以及網絡擁塞。而 pull 模式則能夠根據 consumer 的消費能力以適當的速率消費消息。
pull 模式不足之處是,若是 Kafka 沒有數據,消費者可能會陷入循環中,一直返回空數據。由於消費者從 broker 主動拉取數據,須要維護一個長輪詢,針對這一點, Kafka 的消費者在消費數據時會傳入一個時長參數 timeout,若是當前沒有數據可供消費,consumer 會等待一段時間以後再返回,這段時長即爲 timeout。

6.2 分區分配策略

一個 consumer group 中有多個 consumer,一個 topic 有多個 partition,因此必然會涉及到 partition 的分配問題,即肯定哪一個 partition 由哪一個 consumer 來消費。
Kafka 有兩種分配策略,一個是 RoundRobin,一個是 Range,默認爲range,當消費者組內消費者發生變化時,會觸發分區分配策略(方法從新分配)。
(1) RoundRobin

roundrobin 分區分配

RoundRobin 輪詢方式將分區全部做爲一個總體進行 hash 排序,消費者組內分配分區個數最大差異爲1,是按照組來分的,能夠解決多個消費者消費數據不均衡的問題。
可是,當消費者組內訂閱不一樣主題時,可能形成消費混亂,以下圖所示,consumer0 訂閱主題A,consumer1 訂閱主題B,將 A、B主題的分區排序後分配給消費者組,TopicB 分區中的數據可能分配到 consumer0 中。
roundrobin 分區分配-消費者組訂閱多個主題

(2)Range
range 分區分配

range 方式是按照主題來分的,不會產生輪詢方式的消費混亂問題。
可是,以下圖所示,consumer0、consumer1 同時訂閱了主題A和B,可能形成消息分配不對等問題,當消費者組內訂閱的主題越多,分區分配可能越不均衡。
range 分區分配-消費者組訂閱多個主題

6.3 offset 的維護

因爲 consumer 在消費過程當中可能會出現斷電宕機等故障,consumer 恢復後,須要從故障前的位置繼續消費,因此 consumer 須要實時記錄本身消費到了哪一個 offset,以便故障恢復後繼續消費。
Kafka 0.9 版本以前,consumer 默認將 offset 保存在 Zookeeper 中,從 0.9 版本開始,consumer 默認將 offset 保存在 Kafka 一個內置的 topic 中,該 topic 爲 __consumer_offsets。

剛剛和你們一塊兒深刻探討了 Kafka 的架構,比較偏重理論和基礎,這是掌握 Kafka 的必要內容,接下來我會以代碼和實例的方式,更新 Kafka 有關 API 以及事務、攔截器、監控等高級篇,讓你們完全理解而且會用 Kafka。若是對你有幫助,點個贊相互鼓勵一下吧~

相關文章
相關標籤/搜索