1. 程式人生 > >kafka儲存機制

kafka儲存機制

(一)關鍵術語

1.Broker:訊息中介軟體處理結點,一個Kafka節點就是一個broker,多個broker能夠組成一個Kafka叢集。

2.Topic:一類訊息,比如page view日誌、click日誌等都能夠以topic的形式存在。Kafka叢集能夠同一時候負責多個topic的分發。

3.Partition:topic物理上的分組。一個topic能夠分為多個partition,每一個partition是一個有序的佇列。

4.Segment:partition物理上由多個segment組成。以下有具體說明。

5.offset:每一個partition都由一系列有序的、不可變的訊息組成,這些訊息被連續的追加到partition中。partition中的每一個訊息都有一個連續的序列號叫做offset,用於partition中唯一標識的這條訊息。

二、Kafka檔案儲存基本結構

在Kafka檔案儲存中,同一個topic下有多個不同partition,每個partition為一個分割槽,partiton命名規則為topic名稱+有序序號,第一個partiton序號從0開始,序號最大值為partitions數量減1。
每個partion(分割槽)相當於一個巨型檔案被平均分配到多個大小相等segment(段)資料檔案中。但每個段segment file訊息數量不一定相等,這種特性方便old segment file快速被刪除。預設保留7天的資料。

每個partiton只需要支援順序讀寫就行了,segment檔案生命週期由服務端配置引數決定。(什麼時候建立,什麼時候刪除)## 分析過程分為以下4個步驟:
在這裡插入圖片描述


資料有序的討論?
一個partition的資料是否是有序的? 間隔性有序,不連續
針對一個topic裡面的資料,只能做到partition內部有序,不能做到全域性有序。
特別加入消費者的場景後,如何保證消費者消費的資料全域性有序的?偽命題。

只有一種情況下才能保證全域性有序?就是隻有一個partition。

分析過程分為以下4個步驟

1.topic中partition儲存分佈
2.partiton中檔案儲存方式
3.partiton中segment檔案儲存結構
4.在partition中怎樣通過offset查詢mess

1.topic中partition儲存分佈

如果實驗環境中Kafka叢集僅僅有一個broker。xxx/message-folder為資料檔案儲存根資料夾。在Kafka broker中server.properties檔案配置(引數log.dirs=xxx/message-folder)。比如建立2個topic名稱分別為report_push、launch_info, partitions數量都為partitions=4
儲存路徑和資料夾規則為:
xxx/message-folder
|–report_push-0
|–report_push-1
|–report_push-2
|–report_push-3
|–launch_info-0
|–launch_info-1
|–launch_info-2
|–launch_info-3
在Kafka檔案儲存中,同一個topic下有多個不同partition,每一個partition為一個資料夾,partiton命名規則為topic名稱+有序序號,第一個partiton序號從0開始,序號最大值為partitions數量減1。

如果是多broker分佈情況,請參考kafka叢集partition分佈原理分析

2.partiton中檔案儲存方式

以下示意圖形象說明了partition中檔案儲存方式:
在這裡插入圖片描述
每一個partion(資料夾)相當於一個巨型檔案被平均分配到多個大小相等segment(段)資料檔案裡。

但每一個段segment file訊息數量不一定相等,這樣的特性方便old segment file高速被刪除。(預設情況下每一個檔案大小為1G)

每一個partiton僅僅須要支援順序讀寫即可了。segment檔案生命週期由服務端配置引數決定。

這樣做的優點就是能高速刪除無用檔案。有效提高磁碟利用率。

3.partiton中segment檔案儲存結構

segment file組成:由2大部分組成。分別為index file和data file,此2個檔案一一相應,成對出現,字尾”.index”和“.log”分別表示為segment索引檔案、資料檔案.

segment檔案命名規則:partion全域性的第一個segment從0開始,興許每一個segment檔名稱為上一個segment檔案最後一條訊息的offset值。

數值最大為64位long大小。19位數字字元長度,沒有數字用0填充。

以下檔案列表是筆者在Kafka broker上做的一個實驗,建立一個topicXXX包括1 partition,設定每一個segment大小為500MB,並啟動producer向Kafka broker寫入大量資料,例如以下圖2所看到的segment檔案列表形象說明了上述2個規則:
在這裡插入圖片描述
以上述圖2中一對segment file檔案為例。說明segment中index<—->data file相應關係物理結構例如以下:
在這裡插入圖片描述
上述圖3中索引檔案儲存大量元資料,資料檔案儲存大量訊息,索引檔案裡元資料指向相應資料檔案裡message的物理偏移地址。

當中以索引檔案裡元資料3,497為例,依次在資料檔案裡表示第3個message(在全域性partiton表示第368772個message)、以及該訊息的物理偏移地址為497。

從上述圖3瞭解到segment data file由很多message組成,以下具體說明message物理結構例如以下:
在這裡插入圖片描述

4.keyword 解釋說明

8 byte offset 在parition(分割槽)內的每條訊息都有一個有序的id號,這個id號被稱為偏移(offset),它能夠唯一確定每條訊息在parition(分割槽)內的位置。

即offset表示partiion的第多少message
4 byte message size message大小
4 byte CRC32 用crc32校驗message
1 byte “magic” 表示本次公佈Kafka服務程式協議版本號號
1 byte “attributes” 表示為獨立版本號、或標識壓縮型別、或編碼型別。

4 byte key length 表示key的長度,當key為-1時,K byte key欄位不填
K byte key 可選
value bytes payload 表示實際訊息資料。

5.在partition中怎樣通過offset查詢message

比如讀取offset=368776的message,須要通過以下2個步驟查詢。
第一步查詢segment file
上述圖2為例。當中00000000000000000000.index表示最開始的檔案,起始偏移量(offset)為0.第二個檔案00000000000000368769.index的訊息量起始偏移量為368770 = 368769 + 1.相同,第三個檔案00000000000000737337.index的起始偏移量為737338=737337 + 1。其它興許檔案依次類推。以起始偏移量命名並排序這些檔案,僅僅要依據offset 二分查詢檔案列表,就能夠高速定位到具體檔案。
當offset=368776時定位到00000000000000368769.index|log

第二步通過segment file查詢message
通過第一步定位到segment file,當offset=368776時。依次定位到00000000000000368769.index的元資料物理位置和00000000000000368769.log的物理偏移地址,然後再通過00000000000000368769.log順序查詢直到offset=368776為止。

從上述圖3可知這樣做的優點,segment index file採取稀疏索引儲存方式,它降低索引檔案大小。通過mmap能夠直接記憶體操作,稀疏索引為資料檔案的每一個相應message設定一個元資料指標,它比稠密索引節省了很多其它的儲存空間,但查詢起來須要消耗很多其它的時間。

6.Kafka檔案儲存機制–實際執行效果

實驗環境:

Kafka叢集:由2臺虛擬機器組成

cpu:4核

實體記憶體:8GB

網絡卡:千兆網絡卡

jvm heap: 4GB

具體Kafka服務端配置及其優化請參考:kafka server.properties配置具體解釋
在這裡插入圖片描述

從上述圖5能夠看出,Kafka執行時非常少有大量讀磁碟的操作。主要是定期批量寫磁碟操作。因此操作磁碟非常高效。

這跟Kafka檔案儲存中讀寫message的設計是息息相關的。Kafka中讀寫message有例如以下特點:
寫message
訊息從java堆轉入page cache(即實體記憶體)。
由非同步執行緒刷盤,訊息從page cache刷入磁碟。
讀message
訊息直接從page cache轉入socket傳送出去。
當從page cache沒有找到相應資料時,此時會產生磁碟IO,從磁
盤Load訊息到page cache,然後直接從socket發出去

7.總結

Kafka高效檔案儲存設計特點
1.Kafka把topic中一個parition大檔案分成多個小檔案段。通過多個小檔案段,就easy定期清除或刪除已經消費完檔案。降低磁碟佔用。

2.通過索引資訊能夠高速定位message和確定response的最大大小。

3.通過index元資料所有對映到memory,能夠避免segment file的IO磁碟操作。

4.通過索引檔案稀疏儲存,能夠大幅降低index檔案元資料佔用空間大小。

轉https://www.cnblogs.com/cynchanpin/p/7339537.html

kafka為什麼快

不同於Redis和MemcacheQ等記憶體訊息佇列,Kafka的設計是把所有的Message都要寫入速度低容量大的硬碟,以此來換取更強的儲存能力。實際上,Kafka使用硬碟並沒有帶來過多的效能損失,“規規矩矩”的抄了一條“近道”。

首先,說“規規矩矩”是因為Kafka在磁碟上只做Sequence I/O,由於訊息系統讀寫的特殊性,這並不存在什麼問題。關於磁碟I/O的效能,引用一組Kafka官方給出的測試資料(Raid-5,7200rpm):

Sequence I/O: 600MB/s
Random I/O: 100KB/s

所以通過只做Sequence I/O的限制,規避了磁碟訪問速度低下對效能可能造成的影響。

接下來我們再聊一聊Kafka是如何“抄近道的”。

首先,Kafka重度依賴底層作業系統提供的PageCache功能。當上層有寫操作時,作業系統只是將資料寫入PageCache,同時標記Page屬性為Dirty。

**當讀操作發生時,先從PageCache中查詢,如果發生缺頁才進行磁碟排程,最終返回需要的資料。**實際上PageCache是把儘可能多的空閒記憶體都當做了磁碟快取來使用。同時如果有其他程序申請記憶體,回收PageCache的代價又很小,所以現代的OS都支援PageCache。

使用PageCache功能同時可以避免在JVM內部快取資料,JVM為我們提供了強大的GC能力,同時也引入了一些問題不適用與Kafka的設計。
如果在Heap內管理快取,JVM的GC執行緒會頻繁掃描Heap空間,帶來不必要的開銷。如果Heap過大,執行一次Full GC對系統的可用性來說將是極大的挑戰。
所有在在JVM內的物件都不免帶有一個Object Overhead(千萬不可小視),記憶體的有效空間利用率會因此降低。
所有的In-Process Cache在OS中都有一份同樣的PageCache。所以通過將快取只放在PageCache,可以至少讓可用快取空間翻倍。
如果Kafka重啟,所有的In-Process Cache都會失效,而OS管理的PageCache依然可以繼續使用。

PageCache還只是第一步,Kafka為了進一步的優化效能還採用了Sendfile技術。在解釋Sendfile之前,首先介紹一下傳統的網路I/O操作流程,大體上分為以下4步。

OS 從硬碟把資料讀到核心區的PageCache。
使用者程序把資料從核心區Copy到使用者區。
然後使用者程序再把資料寫入到Socket,資料流入核心區的Socket Buffer上。
OS 再把資料從Buffer中Copy到網絡卡的Buffer上,這樣完成一次傳送。
在這裡插入圖片描述
整個過程共經歷兩次Context Switch,四次System Call。同一份資料在核心Buffer與使用者Buffer之間重複拷貝,效率低下。其中2、3兩步沒有必要,完全可以直接在核心區完成資料拷貝。這也正是Sendfile所解決的問題,經過Sendfile優化後,整個I/O過程就變成了下面這個樣子。