Kafka底層原理剖析(近萬字建議收藏)

Kafka 簡介

Apache Kafka 是一個分佈式發佈-訂閱消息系統。是大數據領域消息隊列中惟一的王者。最初由 linkedin 公司使用 scala 語言開發,在2010年貢獻給了Apache基金會併成爲頂級開源項目。至今已有十餘年,仍然是大數據領域不可或缺的而且是愈來愈重要的一個組件。shell

Kafka 適合離線和在線消息,消息保留在磁盤上,並在集羣內複製以防止數據丟失。kafka構建在zookeeper同步服務之上。它與 Flink 和 Spark 有很是好的集成,應用於實時流式數據分析。服務器

Kafka特色:網絡

  1. 可靠性:具備副本及容錯機制。
  2. 可擴展性:kafka無需停機便可擴展節點及節點上線。
  3. 持久性:數據存儲到磁盤上,持久性保存。
  4. 性能:kafka具備高吞吐量。達到TB級的數據,也有很是穩定的性能。
  5. 速度快:順序寫入和零拷貝技術使得kafka延遲控制在毫秒級。

Kafka 底層原理

先看下 Kafka 系統的架構架構

Kafka 架構

kafka支持消息持久化,消費端是主動拉取數據,消費狀態和訂閱關係由客戶端負責維護,消息消費完後,不會當即刪除,會保留歷史消息。所以支持多訂閱時,消息只會存儲一份就能夠。併發

  1. broker:kafka集羣中包含一個或者多個服務實例(節點),這種服務實例被稱爲broker(一個broker就是一個節點/一個服務器);
  2. topic:每條發佈到kafka集羣的消息都屬於某個類別,這個類別就叫作topic;
  3. partition:partition是一個物理上的概念,每一個topic包含一個或者多個partition;
  4. segment:一個partition當中存在多個segment文件段,每一個segment分爲兩部分,.log文件和 .index 文件,其中 .index 文件是索引文件,主要用於快速查詢, .log 文件當中數據的偏移量位置;
  5. producer:消息的生產者,負責發佈消息到 kafka 的 broker 中;
  6. consumer:消息的消費者,向 kafka 的 broker 中讀取消息的客戶端;
  7. consumer group:消費者組,每個 consumer 屬於一個特定的 consumer group(能夠爲每一個consumer指定 groupName);
  8. .log:存放數據文件;
  9. .index:存放.log文件的索引數據。

Kafka 主要組件

1. producer(生產者)

producer主要是用於生產消息,是kafka當中的消息生產者,生產的消息經過topic進行歸類,保存到kafka的broker裏面去。異步

2. topic(主題)

  1. kafka將消息以topic爲單位進行歸類;
  2. topic特指kafka處理的消息源(feeds of messages)的不一樣分類;
  3. topic是一種分類或者發佈的一些列記錄的名義上的名字。kafka主題始終是支持多用戶訂閱的;也就是說,一 個主題能夠有零個,一個或者多個消費者訂閱寫入的數據;
  4. 在kafka集羣中,能夠有無數的主題;
  5. 生產者和消費者消費數據通常以主題爲單位。更細粒度能夠到分區級別。

3. partition(分區)

kafka當中,topic是消息的歸類,一個topic能夠有多個分區(partition),每一個分區保存部分topic的數據,全部的partition當中的數據所有合併起來,就是一個topic當中的全部的數據。分佈式

一個broker服務下,能夠建立多個分區,broker數與分區數沒有關係;
在kafka中,每個分區會有一個編號:編號從0開始。
每個分區內的數據是有序的,但全局的數據不能保證是有序的。(有序是指生產什麼樣順序,消費時也是什麼樣的順序)函數

4. consumer(消費者)

consumer是kafka當中的消費者,主要用於消費kafka當中的數據,消費者必定是歸屬於某個消費組中的。性能

5. consumer group(消費者組)

消費者組由一個或者多個消費者組成,同一個組中的消費者對於同一條消息只消費一次大數據

每一個消費者都屬於某個消費者組,若是不指定,那麼全部的消費者都屬於默認的組。

每一個消費者組都有一個ID,即group ID。組內的全部消費者協調在一塊兒來消費一個訂閱主題( topic)的全部分區(partition)。固然,每一個分區只能由同一個消費組內的一個消費者(consumer)來消費,能夠由不一樣的消費組來消費。

partition數量決定了每一個consumer group中併發消費者的最大數量。以下圖:

示例 1

如上面左圖所示,若是隻有兩個分區,即便一個組內的消費者有4個,也會有兩個空閒的。
如上面右圖所示,有4個分區,每一個消費者消費一個分區,併發量達到最大4。

在來看以下一幅圖:

示例 2

如上圖所示,不一樣的消費者組消費同一個topic,這個topic有4個分區,分佈在兩個節點上。左邊的 消費組1有兩個消費者,每一個消費者就要消費兩個分區才能把消息完整的消費完,右邊的 消費組2有四個消費者,每一個消費者消費一個分區便可。

總結下kafka中分區與消費組的關係

消費組: 由一個或者多個消費者組成,同一個組中的消費者對於同一條消息只消費一次。
某一個主題下的分區數,對於消費該主題的同一個消費組下的消費者數量,應該小於等於該主題下的分區數

如:某一個主題有4個分區,那麼消費組中的消費者應該小於等於4,並且最好與分區數成整數倍 1 2 4 這樣。同一個分區下的數據,在同一時刻,不能同一個消費組的不一樣消費者消費

總結:分區數越多,同一時間能夠有越多的消費者來進行消費,消費數據的速度就會越快,提升消費的性能

6. partition replicas(分區副本)

kafka 中的分區副本以下圖所示:

kafka 分區副本

副本數(replication-factor):控制消息保存在幾個broker(服務器)上,通常狀況下副本數等於broker的個數。

一個broker服務下,不能夠建立多個副本因子。建立主題時,副本因子應該小於等於可用的broker數

副本因子操做以分區爲單位的。每一個分區都有各自的主副本和從副本;

主副本叫作leader,從副本叫作 follower(在有多個副本的狀況下,kafka會爲同一個分區下的全部分區,設定角色關係:一個leader和N個 follower),處於同步狀態的副本叫作in-sync-replicas(ISR);

follower經過拉的方式從leader同步數據。
消費者和生產者都是從leader讀寫數據,不與follower交互

副本因子的做用:讓kafka讀取數據和寫入數據時的可靠性。

副本因子是包含自己,同一個副本因子不能放在同一個broker中。

若是某一個分區有三個副本因子,就算其中一個掛掉,那麼只會剩下的兩個中,選擇一個leader,但不會在其餘的broker中,另啓動一個副本(由於在另外一臺啓動的話,存在數據傳遞,只要在機器之間有數據傳遞,就會長時間佔用網絡IO,kafka是一個高吞吐量的消息系統,這個狀況不容許發生)因此不會在另外一個broker中啓動。

若是全部的副本都掛了,生產者若是生產數據到指定分區的話,將寫入不成功。

lsr表示:當前可用的副本。

7. segment文件

一個partition當中由多個segment文件組成,每一個segment文件,包含兩部分,一個是 .log 文件,另一個是 .index 文件,其中 .log 文件包含了咱們發送的數據存儲,.index 文件,記錄的是咱們.log文件的數據索引值,以便於咱們加快數據的查詢速度。

索引文件與數據文件的關係

既然它們是一一對應成對出現,必然有關係。索引文件中元數據指向對應數據文件中message的物理偏移地址。

好比索引文件中 3,497 表明:數據文件中的第三個message,它的偏移地址爲497。

再來看數據文件中,Message 368772表示:在全局partiton中是第368772個message。

注:segment index file 採起稀疏索引存儲方式,減小索引文件大小,經過mmap(內存映射)能夠直接內存操做,稀疏索引爲數據文件的每一個對應message設置一個元數據指針,它比稠密索引節省了更多的存儲空間,但查找起來須要消耗更多的時間。

.index 與 .log 對應關係以下:

.index 與 .log

上圖左半部分是索引文件,裏面存儲的是一對一對的key-value,其中key是消息在數據文件(對應的log文件)中的編號,好比「1,3,6,8……」,
分別表示在log文件中的第1條消息、第3條消息、第6條消息、第8條消息……

那麼爲何在index文件中這些編號不是連續的呢?
這是由於index文件中並無爲數據文件中的每條消息都創建索引,而是採用了稀疏存儲的方式,每隔必定字節的數據創建一條索引。
這樣避免了索引文件佔用過多的空間,從而能夠將索引文件保留在內存中。
但缺點是沒有創建索引的Message也不能一次定位到其在數據文件的位置,從而須要作一次順序掃描,可是此次順序掃描的範圍就很小了。

value 表明的是在全局partiton中的第幾個消息。

以索引文件中元數據 3,497 爲例,其中3表明在右邊log數據文件中從上到下第3個消息,
497表示該消息的物理偏移地址(位置)爲497(也是在全局partiton表示第497個消息)。

log日誌目錄及組成
kafka在咱們指定的log.dir目錄下,會建立一些文件夾;名字是 (主題名字-分區名) 所組成的文件夾。 在(主題名字-分區名)的目錄下,會有兩個文件存在,以下所示:

#索引文件
00000000000000000000.index
#日誌內容
00000000000000000000.log

在目錄下的文件,會根據log日誌的大小進行切分,.log文件的大小爲1G的時候,就會進行切分文件;以下:

-rw-r--r--. 1 root root 389k  1月  17  18:03   00000000000000000000.index
-rw-r--r--. 1 root root 1.0G  1月  17  18:03   00000000000000000000.log
-rw-r--r--. 1 root root  10M  1月  17  18:03   00000000000000077894.index
-rw-r--r--. 1 root root 127M  1月  17  18:03   00000000000000077894.log

在kafka的設計中,將offset值做爲了文件名的一部分。

segment文件命名規則:partion全局的第一個segment從0開始,後續每一個segment文件名爲上一個全局 partion的最大offset(偏移message數)。數值最大爲64位long大小,20位數字字符長度,沒有數字就用 0 填充。

經過索引信息能夠快速定位到message。經過index元數據所有映射到內存,能夠避免segment File的IO磁盤操做;

經過索引文件稀疏存儲,能夠大幅下降index文件元數據佔用空間大小。

稀疏索引:爲了數據建立索引,但範圍並非爲每一條建立,而是爲某一個區間建立;
好處:就是能夠減小索引值的數量。
很差的地方:找到索引區間以後,要得進行第二次處理。

8. message的物理結構

生產者發送到kafka的每條消息,都被kafka包裝成了一個message

message 的物理結構以下圖所示:

.index 與 .log

因此生產者發送給kafka的消息並非直接存儲起來,而是通過kafka的包裝,每條消息都是上圖這個結構,只有最後一個字段纔是真正生產者發送的消息數據。

kafka中的數據不丟失機制

1. 生產者生產數據不丟失

發送消息方式

生產者發送給kafka數據,能夠採用同步方式異步方式

同步方式

發送一批數據給kafka後,等待kafka返回結果:

  1. 生產者等待10s,若是broker沒有給出ack響應,就認爲失敗。
  2. 生產者重試3次,若是尚未響應,就報錯.

異步方式

發送一批數據給kafka,只是提供一個回調函數:

  1. 先將數據保存在生產者端的buffer中。buffer大小是2萬條 。
  2. 知足數據閾值或者數量閾值其中的一個條件就能夠發送數據。
  3. 發送一批數據的大小是500條。

注:若是broker遲遲不給ack,而buffer又滿了,開發者能夠設置是否直接清空buffer中的數據。

ack機制(確認機制)

生產者數據發送出去,須要服務端返回一個確認碼,即ack響應碼;ack的響應有三個狀態值0,1,-1

0:生產者只負責發送數據,不關心數據是否丟失,丟失的數據,須要再次發送

1:partition的leader收到數據,無論follow是否同步完數據,響應的狀態碼爲1

-1:全部的從節點都收到數據,響應的狀態碼爲-1

若是broker端一直不返回ack狀態,producer永遠不知道是否成功;producer能夠設置一個超時時間10s,超過期間認爲失敗。

2. broker中數據不丟失

在broker中,保證數據不丟失主要是經過副本因子(冗餘),防止數據丟失。

3. 消費者消費數據不丟失

在消費者消費數據的時候,只要每一個消費者記錄好offset值便可,就能保證數據不丟失。也就是須要咱們本身維護偏移量(offset),可保存在 Redis 中。

搜索公衆號:五分鐘學大數據,回覆 祕籍 便可獲取上百本大數據書籍;回覆 簡歷 獲取幾十份大數據簡歷模板

或直接掃描下方二維碼

.index 與 .log

相關文章
相關標籤/搜索