Apache Kafka 是一個分佈式發佈-訂閱消息系統。是大數據領域消息隊列中惟一的王者。最初由 linkedin 公司使用 scala 語言開發,在2010年貢獻給了Apache基金會併成爲頂級開源項目。至今已有十餘年,仍然是大數據領域不可或缺的而且是愈來愈重要的一個組件。shell
Kafka 適合離線和在線消息,消息保留在磁盤上,並在集羣內複製以防止數據丟失。kafka構建在zookeeper同步服務之上。它與 Flink 和 Spark 有很是好的集成,應用於實時流式數據分析。服務器
Kafka特色:網絡
先看下 Kafka 系統的架構架構
kafka支持消息持久化,消費端是主動拉取數據,消費狀態和訂閱關係由客戶端負責維護,消息消費完後,不會當即刪除,會保留歷史消息。所以支持多訂閱時,消息只會存儲一份就能夠。併發
producer主要是用於生產消息,是kafka當中的消息生產者,生產的消息經過topic進行歸類,保存到kafka的broker裏面去。異步
kafka當中,topic是消息的歸類,一個topic能夠有多個分區(partition),每一個分區保存部分topic的數據,全部的partition當中的數據所有合併起來,就是一個topic當中的全部的數據。分佈式
一個broker服務下,能夠建立多個分區,broker數與分區數沒有關係;
在kafka中,每個分區會有一個編號:編號從0開始。
每個分區內的數據是有序的,但全局的數據不能保證是有序的。(有序是指生產什麼樣順序,消費時也是什麼樣的順序)函數
consumer是kafka當中的消費者,主要用於消費kafka當中的數據,消費者必定是歸屬於某個消費組中的。性能
消費者組由一個或者多個消費者組成,同一個組中的消費者對於同一條消息只消費一次。大數據
每一個消費者都屬於某個消費者組,若是不指定,那麼全部的消費者都屬於默認的組。
每一個消費者組都有一個ID,即group ID。組內的全部消費者協調在一塊兒來消費一個訂閱主題( topic)的全部分區(partition)。固然,每一個分區只能由同一個消費組內的一個消費者(consumer)來消費,能夠由不一樣的消費組來消費。
partition數量決定了每一個consumer group中併發消費者的最大數量。以下圖:
如上面左圖所示,若是隻有兩個分區,即便一個組內的消費者有4個,也會有兩個空閒的。
如上面右圖所示,有4個分區,每一個消費者消費一個分區,併發量達到最大4。
在來看以下一幅圖:
如上圖所示,不一樣的消費者組消費同一個topic,這個topic有4個分區,分佈在兩個節點上。左邊的 消費組1有兩個消費者,每一個消費者就要消費兩個分區才能把消息完整的消費完,右邊的 消費組2有四個消費者,每一個消費者消費一個分區便可。
總結下kafka中分區與消費組的關係:
消費組: 由一個或者多個消費者組成,同一個組中的消費者對於同一條消息只消費一次。
某一個主題下的分區數,對於消費該主題的同一個消費組下的消費者數量,應該小於等於該主題下的分區數。
如:某一個主題有4個分區,那麼消費組中的消費者應該小於等於4,並且最好與分區數成整數倍 1 2 4 這樣。同一個分區下的數據,在同一時刻,不能同一個消費組的不一樣消費者消費。
總結:分區數越多,同一時間能夠有越多的消費者來進行消費,消費數據的速度就會越快,提升消費的性能。
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表示:當前可用的副本。
一個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 對應關係以下:
上圖左半部分是索引文件,裏面存儲的是一對一對的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文件元數據佔用空間大小。
稀疏索引:爲了數據建立索引,但範圍並非爲每一條建立,而是爲某一個區間建立;
好處:就是能夠減小索引值的數量。
很差的地方:找到索引區間以後,要得進行第二次處理。
生產者發送到kafka的每條消息,都被kafka包裝成了一個message
message 的物理結構以下圖所示:
因此生產者發送給kafka的消息並非直接存儲起來,而是通過kafka的包裝,每條消息都是上圖這個結構,只有最後一個字段纔是真正生產者發送的消息數據。
生產者發送給kafka數據,能夠採用同步方式或異步方式
同步方式:
發送一批數據給kafka後,等待kafka返回結果:
異步方式:
發送一批數據給kafka,只是提供一個回調函數:
注:若是broker遲遲不給ack,而buffer又滿了,開發者能夠設置是否直接清空buffer中的數據。
生產者數據發送出去,須要服務端返回一個確認碼,即ack響應碼;ack的響應有三個狀態值0,1,-1
0:生產者只負責發送數據,不關心數據是否丟失,丟失的數據,須要再次發送
1:partition的leader收到數據,無論follow是否同步完數據,響應的狀態碼爲1
-1:全部的從節點都收到數據,響應的狀態碼爲-1
若是broker端一直不返回ack狀態,producer永遠不知道是否成功;producer能夠設置一個超時時間10s,超過期間認爲失敗。
在broker中,保證數據不丟失主要是經過副本因子(冗餘),防止數據丟失。
在消費者消費數據的時候,只要每一個消費者記錄好offset值便可,就能保證數據不丟失。也就是須要咱們本身維護偏移量(offset),可保存在 Redis 中。
或直接掃描下方二維碼