原文 https://www.cnblogs.com/dorothychai/p/6181058.htmlhtml
Kafka中的Message是以topic爲基本單位組織的,不一樣的topic之間是相互獨立的。每一個topic又能夠分紅幾個不一樣的partition(每一個topic有幾個partition是在建立topic時指定的),每一個partition存儲一部分Message。借用官方的一張圖,能夠直觀地看到topic和partition的關係。app
partition是以文件的形式存儲在文件系統中,好比,建立了一個名爲page_visits的topic,其有5個partition,那麼在Kafka的數據目錄中(由配置文件中的log.dirs指定的)中就有這樣5個目錄: page_visits-0, page_visits-1,page_visits-2,page_visits-3,page_visits-4,其命名規則爲<topic_name>-<partition_id>,裏面存儲的分別就是這5個partition的數據。atom
接下來,本文將分析partition目錄中的文件的存儲格式和相關的代碼所在的位置。spa
Partition中的每條Message由offset來表示它在這個partition中的偏移量,這個offset不是該Message在partition數據文件中的實際存儲位置,而是邏輯上一個值,它惟一肯定了partition中的一條Message。所以,能夠認爲offset是partition中Message的id。partition中的每條Message包含了如下三個屬性:.net
其中offset爲long型,MessageSize爲int32,表示data有多大,data爲message的具體內容。它的格式和Kafka通信協議中介紹的MessageSet格式是一致。指針
Partition的數據文件則包含了若干條上述格式的Message,按offset由小到大排列在一塊兒。它的實現類爲FileMessageSet,類圖以下:
它的主要方法以下:htm
咱們來思考一下,若是一個partition只有一個數據文件會怎麼樣?blog
那Kafka是如何解決查找效率的的問題呢?有兩大法寶:1) 分段 2) 索引。索引
Kafka解決查詢效率的手段之一是將數據文件分段,好比有100條Message,它們的offset是從0到99。假設將數據文件分紅5段,第一段爲0-19,第二段爲20-39,以此類推,每段放在一個單獨的數據文件裏面,數據文件以該段中最小的offset命名。這樣在查找指定offset的Message的時候,用二分查找就能夠定位到該Message在哪一個段中。內存
數據文件分段使得能夠在一個較小的數據文件中查找對應offset的Message了,可是這依然須要順序掃描才能找到對應offset的Message。爲了進一步提升查找的效率,Kafka爲每一個分段後的數據文件創建了索引文件,文件名與數據文件的名字是同樣的,只是文件擴展名爲.index。
索引文件中包含若干個索引條目,每一個條目表示數據文件中一條Message的索引。索引包含兩個部分(均爲4個字節的數字),分別爲相對offset和position。
index文件中並無爲數據文件中的每條Message創建索引,而是採用了稀疏存儲的方式,每隔必定字節的數據創建一條索引。這樣避免了索引文件佔用過多的空間,從而能夠將索引文件保留在內存中。但缺點是沒有創建索引的Message也不能一次定位到其在數據文件的位置,從而須要作一次順序掃描,可是此次順序掃描的範圍就很小了。
在Kafka中,索引文件的實現類爲OffsetIndex,它的類圖以下:
主要的方法有:
咱們以幾張圖來總結一下Message是如何在Kafka中存儲的,以及如何查找指定offset的Message的。
Message是按照topic來組織,每一個topic能夠分紅多個的partition,好比:有5個partition的名爲爲page_visits的topic的目錄結構爲:
partition是分段的,每一個段叫LogSegment,包括了一個數據文件和一個索引文件,下圖是某個partition目錄下的文件:
能夠看到,這個partition有4個LogSegment。
借用博主@lizhitao博客上的一張圖來展現是如何查找Message的。
好比:要查找絕對offset爲7的Message:
這套機制是創建在offset是有序的。索引文件被映射到內存中,因此查找的速度仍是很快的。
一句話,Kafka的Message存儲採用了分區(partition),分段(LogSegment)和稀疏索引這幾個手段來達到了高效性。