Kafka文件的存儲機制


Kafka文件的存儲機制

同一個topic下有多個不同的partition,每個partition為一個目錄,partition命名的規則是topic的名稱加上一個序號,序號從0開始。

每一個partition目錄下的文件被平均切割成大小相等(默認一個文件是500兆,可以手動去設置)的數據文件,
每一個數據文件都被稱為一個段(segment file),但每個段消息數量不一定相等,這種特性能夠使得老的segment可以被快速清除。
默認保留7天的數據。

 

每個partition下都會有這些每500兆一個每500兆一個(當然在上面的測試中我們將它設置為了1G一個)的segment段。

 

另外每個partition只需要支持順序讀寫就可以了,partition中的每一個segment端的生命周期是由我們在配置文件中指定的一個參數覺得的。
比如它在默認情況下,每滿500兆就會創建新的segment段(segment file),每滿7天就會清理之前的數據。
它的一個特點就是支持順序寫。如下圖所示:

 

首先00000000000000000000.log文件是最早產生的文件,該文件達到1G(因為我們在配置文件里面指定的1G大小,默認情況下是500兆)
之后又產生了新的0000000000000672348.log文件,新的數據會往這個新的文件里面寫,這個文件達到1G之后,數據就會再往下一個文件里面寫,
也就是說它只會往文件的末尾追加數據,這就是順序寫的過程,生產者只會對每一個partition做數據的追加(寫)的操作。
問題:如何保證消息消費的有序性呢?比如說生產者生產了0到100個商品,那么消費者在消費的時候安裝0到100這個從小到大的順序消費,
那么kafka如何保證這種有序性呢?難度就在於,生產者生產出0到100這100條數據之后,通過一定的分組策略存儲到broker的partition中的時候,
比如0到10這10條消息被存到了這個partition中,10到20這10條消息被存到了那個partition中,這樣的話,消息在分組存到partition中的時候就已經被分組策略搞得無序了。
那么能否做到消費者在消費消息的時候全局有序呢?遇到這個問題,我們可以回答,在大多數情況下是做不到全局有序的。但在某些情況下是可以做到的。 比如我的partition只有一個,這種情況下是可以全局有序的。那么可能有人又要問了,只有一個partition的話,哪里來的分布式呢?哪里來的負載均衡呢?
所以說,全局有序是一個偽命題!全局有序根本沒有辦法在kafka要實現的大數據的場景來做到。但是我們只能保證當前這個partition內部消息消費的有序性。 結論:一個partition中的數據是有序的嗎?回答:間隔有序,不連續。 針對一個topic里面的數據,只能做到partition內部有序,不能做到全局有序。特別是加入消費者的場景后,如何保證消費者的消費的消息的全局有序性,
這是一個偽命題,只有在一種情況下才能保證消費的消息的全局有序性,那就是只有一個partition!。
Segment file是什么?

生產者生產的消息按照一定的分組策略被發送到broker中partition中的時候,這些消息如果在內存中放不下了,就會放在文件中,
partition在磁盤上就是一個目錄,該目錄名是topic的名稱加上一個序號,在這個partition目錄下,有兩類文件,一類是以log為后綴的文件,
一類是以index為后綴的文件,每一個log文件和一個index文件相對應,這一對文件就是一個segment file,也就是一個段。
其中的log文件就是數據文件,里面存放的就是消息,而index文件是索引文件,索引文件記錄了元數據信息。
說到segment file的索引文件和數據文件的一一對應,我們應該能想到storm中的Ack File機制,在spout發出去的時候要發一個Ack Tuple,
在下游的bolt處理完之后,它也要發一個Ack Tuple,這兩個Ack Tuple里面包含了同樣一份數據,這個數據叫做MessageId,它是一個對象,
這個對象里面包含兩個比較重要的字段,一個是RootId,另一個是TupleId(也叫錨點Id),這個錨點Id會在我們發送數據的時候進行異或一下,
異或的結果才會發送給Ack那個Bolt。

Segment文件命名的規則:partition全局的第一個segment從0(20個0)開始,后續的每一個segment文件名是上一個segment文件中最后一條消息的offset值。

那么這樣命令有什么好處呢?假如我們有一個消費者已經消費到了368776(offset值為368776),那么現在我們要繼續消費的話,怎么做呢?
看上圖,分2個步驟,第1步是從所有文件log文件的的文件名中找到對應的log文件,第368776條數據位於上圖中的“
00000000000000368769.log”這個文件中,
這一步涉及到一個常用的算法叫做“二分查找法”(假如我現在給你一個offset值讓你去找,你首先是將所有的log的文件名進行排序,然后通過二分查找法進行查找,
很快就能定位到某一個文件,緊接着拿着這個offset值到其索引文件中找這條數據究竟存在哪里);第2步是到index文件中去找第368776條數據所在的位置。 索引文件(index文件)中存儲這大量的元數據,而數據文件(log文件)中存儲這大量的消息。 索引文件(index文件)中的元數據指向對應的數據文件(log文件)中消息的物理偏移地址。

上圖的左半部分是索引文件,里面存儲的是一對一對的key-value,其中key是消息在數據文件(對應的log文件)中的編號,比如“1,3,6,8……”,
分別表示在log文件中的第1條消息、第3條消息、第6條消息、第8條消息……,那么為什么在index文件中這些編號不是連續的呢?
這是因為index文件中並沒有為數據文件中的每條消息都建立索引,而是采用了稀疏存儲的方式,每隔一定字節的數據建立一條索引。
這樣避免了索引文件占用過多的空間,從而可以將索引文件保留在內存中。
但缺點是沒有建立索引的Message也不能一次定位到其在數據文件的位置,從而需要做一次順序掃描,但是這次順序掃描的范圍就很小了。 其中以索引文件中元數據3,497為例,其中3代表在右邊log數據文件中從上到下第3個消息(在全局partiton表示第368772個消息),
其中497表示該消息的物理偏移地址(位置)為497。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM