kafka的幾個重要概念
Broker
:消息中間件處理結點胧华,一個 Kafka 節(jié)點就是一個 broker,多個 broker 可以組成一個 Kafka 集群嗅辣;Topic
:一類消息桐猬,例如 note impressio 日志撑蚌、 click 日志等都可以以 topic 的形式存在上遥,Kafka 集群能夠同時負責多個 topic 的分發(fā);Partition
:topic 物理上的分組争涌,一個 topic 可以分為多個 partition露该,每個 partition 是一個有序的隊;segment
:每個 partition 又由多個segment file組成第煮;offset
:每個 partition 都由一系列有序的解幼、不可變的消息組成,這些消息被連續(xù)的追加到 partition 中包警。partition 中的每個消息都有一個連續(xù)的序列號叫做 offset撵摆,用于 partition 唯一標識一條消息;message
:這個算是 kafka 文件中最小的存儲單位害晦,即是 one commit log特铝。
kafka 的 message 是以 topic 為基本單位,不同 topic 之間是相互獨立的壹瘟。
每個 topic 又可分為幾個不同的 partition鲫剿,每個 partition 存儲一部分 message。
同一個 topic 的不同 partition 可以分布在不同的 broker 上稻轨,這正是分布式的設計灵莲。
partition 是以文件夾的形式存儲在 broker 機器上。
topic 與 partition 的關系如下:
Partition中的文件
segment file
對于一個 partition殴俱,里面又有很多大小相等的 segment 數(shù)據(jù)文件(這個文件的具體大小可以在config/server.properties中進行設置)政冻,這種特性可以方便 old segment file的快速刪除。
下面介紹一下 partition 中的 segment file的組成:
1. segment file 組成:由2部分組成线欲,分別為 index file和 data file明场,這兩個文件是一一對應的,后綴”.index”和”.log”分別表示索引文件和數(shù)據(jù)文件李丰;數(shù)值最大為64位 long 大小苦锨,19位數(shù)字字符長度,沒有數(shù)字用0填充趴泌;
2. 自0.10.0.1開始的kafka segment file組成:多了一部分舟舒,還有 .timeindex 索引文件,基于時間的索引文件踱讨;目前支持的時間戳類型有兩種: CreateTime 和 LogAppendTime 前者表示 producer 創(chuàng)建這條消息的時間魏蔗;后者表示 broker 接收到這條消息的時間(嚴格來說砍的,是 leader broker 將這條消息寫入到 log 的時間)
3. segment file 命名規(guī)則:partition 的第一個 segment 從0開始痹筛,后續(xù)每個 segment 文件名為上一個 segment 文件最后一條消息的 offset, ofsset 的數(shù)值最大為64位(long 類型),20位數(shù)字字符長度,沒有數(shù)字用0填充帚稠。如下圖所示:
老版本 segment file 結構:
新版本 segment file 結構:
4. 關于 segment file 中 index 索引文件與 data 文件對應關系圖谣旁,這里我們借用網(wǎng)上的一個圖片,如下所示:
5. segment的索引文件中存儲著大量的元數(shù)據(jù)滋早,數(shù)據(jù)文件中存儲著大量消息榄审,索引文件中的元數(shù)據(jù)指向對應數(shù)據(jù)文件中的 message 的物理偏移地址。以索引文件中的6杆麸,1407為例搁进,在數(shù)據(jù)文件中表示第6個 message(在全局 partition 表示第368775個 message),以及該消息的物理偏移地址為1407昔头。
注
:.index文件的第一個數(shù)是 message 相對 offset饼问,后面的數(shù)字是該消息的物理偏移地址。
6. message 具體結構如下:
為什么分成多個segment file
1. 問題: 如果 topic 的 partition 中只有一個文件會怎么樣揭斧?
新數(shù)據(jù)加在文件的末尾(調用內部方法)莱革,不論文件多大,該操作的時間復雜度都是O(1)讹开;這個沒問題盅视。
查找某個 offset 的時候,是順序查找旦万。想想闹击,如果文件很大的話,查找的效率就會很低成艘;這個是要解決的拇砰。
2. Kakfa 是如何解決上述問題的呢
通過上述分析發(fā)現(xiàn),如果 Kafka 只有一會文件的話狰腌,插入新數(shù)據(jù)的效率是沒問題的除破;只是在查找的時候,效率很低琼腔。
解決辦法
方法一
數(shù)據(jù)文件分段
將大文件分成多個小的文件瑰枫,便于維護。 由 offset 的起始位置來命名丹莲,則通過二分查找可以確定一個待查找的 offset
屬于在那個小文件里面光坝。
方法二
為數(shù)據(jù)文件建立索引文件
即為上圖中可以看到的 .index 文件, 數(shù)據(jù)分段雖然解決了一個大文件的問題甥材,但是找到具體的小文件后盯另,還是要通過
順序掃描的方式才能找到對應 offset 的 message。 為了提高順序掃描的效率洲赵,kafka 為每個分段后的文件建立了一個
與數(shù)據(jù)文件名一樣的鸳惯,擴展名為 .index 的文件商蕴。
索引文件的內部結構
索引文件包含兩個部分(均為4個字節(jié)),分別為 offset 和 position芝发。
- 相對 offset: 由于數(shù)據(jù)文件分段以后绪商,除了第一個數(shù)據(jù)以外,每個數(shù)據(jù)文件的起始 offset 不為0辅鲸,相對 offset 表示
該 message 相對于其所屬數(shù)據(jù)文件中最小的 offset 的大小格郁,即在每個文件中都是從1開始。 然后查找具體 offset 的時候独悴,
只需要通過二分查找找到具體的在哪個文件中例书,然后在用 offset - 文件名對應的數(shù)值, 即可確定在文件中的相對 offset刻炒。
存儲相對 offset 的好處是可以減小索引文件占用的空間雾叭。
- position: 表示該條 message 在數(shù)據(jù)文件中的絕對位置, 只要打開數(shù)據(jù)文件并移動文件指針到這個 position 就可以
讀取到對應的 message 數(shù)據(jù)了落蝙。
3. 通過 offset 查找 message
分為兩個步驟:
通過
二分查找
文件列表织狐,快速定位到具體的.index和.log文件; 即找到小于或等于給定 offset 的最大的 offset 文件筏勒。通過 segment file 查找具體的 message移迫,找到具體的文件后,先定位到 .index 文件中的 元數(shù)據(jù)物理位置 position管行,
即 .log 文件中的物理偏移地址厨埋。 然后在通過順序查找到具體的 offset。
上述最后還需要順序查找具體的 offset捐顷, 而不是直接通過 position 定位到具體的 message荡陷,是因為 segment index file
沒有為數(shù)據(jù)文件中的每條 message 建立索引,而是采用稀疏索引
的存儲方式迅涮,每隔一定字節(jié)的數(shù)據(jù)建立一條索引废赞,這樣可以減小
索引文件,通過 map 可以直接進行內存操作叮姑, 稀疏索引為數(shù)據(jù)文件的每個對應 message 設置一個元數(shù)據(jù)指針唉地, 這樣比稠密索引
節(jié)省了存儲空間,但是查找時需要消耗更多的時間传透,其實最后通過 .index 文件中 position 無法直接定位到 沒有建立索引
的 message耘沼, 而是需要通過順序查找,再繼續(xù)在 .log 文件中繼續(xù)往下查找朱盐。
總結
Kafka 高效文件存儲設計特點:
將 topic 中一個 partition 大文件分割成多個小文件段群嗤,這樣更容易定期清除和刪除已經(jīng)消費完的文件,減少磁盤占用兵琳。
通過索引可以快速定位到 message 和 確定 response 的最大大小狂秘。
通過 index 元數(shù)據(jù)全部映射到 memory骇径,可以避免 segment file的 IO 磁盤操作。
通過索引文件稀疏存儲赃绊,可以大幅降低 index 文件元數(shù)據(jù)占用空間大小。