1. 程式人生 > >Kafka檔案的儲存機制

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。

複製程式碼

 

好文要頂 關注我 收藏該文  

學不死
關注 - 34
粉絲 - 23

+加關注

4

0

« 上一篇:SecureCRT命令列文字和背景顏色設定
» 下一篇:Kafka訊息保證不丟失和重複消費問題