Kafka這款分布式消息隊(duì)列使用文件系統(tǒng)和操作系統(tǒng)的頁(yè)緩存(page cache)分別存儲(chǔ)和緩存消息,摒棄了Java的堆緩存機(jī)制,同時(shí)將隨機(jī)寫操作改為順序?qū)?,再結(jié)合Zero-Copy的特性極大地改善了IO性能?!耙粔KSATA RAID-5陣列磁盤的線性寫速度可以達(dá)到幾百M(fèi)/s,而隨機(jī)寫的速度只能是100多KB/s,線性寫的速度是隨機(jī)寫的上千倍”,由此可以看出對(duì)磁盤寫消息的速度快慢關(guān)鍵還是取決于我們的使用方法。
Kafka也能夠通過配置讓用戶自己決定已經(jīng)落盤的持久化消息保存的時(shí)間,提供消息處理更為靈活的方式。本文將主要介紹Kafka中數(shù)據(jù)的存儲(chǔ)消息結(jié)構(gòu)、存儲(chǔ)方式以及如何通過offset來(lái)查找消息等內(nèi)容。
-
(1)Broker:消息中間件處理節(jié)點(diǎn),一個(gè)Kafka節(jié)點(diǎn)就是一個(gè)broker,一個(gè)或者多個(gè)Broker可以組成一個(gè)Kafka集群;
(2)Topic:主題是對(duì)一組消息的抽象分類,比如例如page view日志、click日志等都可以以topic的形式進(jìn)行抽象劃分類別。在物理上,不同Topic的消息分開存儲(chǔ),邏輯上一個(gè)Topic的消息雖然保存于一個(gè)或多個(gè)broker上但用戶只需指定消息的Topic即可使得數(shù)據(jù)的生產(chǎn)者或消費(fèi)者不必關(guān)心數(shù)據(jù)存于何處;
(3)Partition:每個(gè)主題又被分成一個(gè)或者若干個(gè)分區(qū)(Partition)。每個(gè)分區(qū)在本地磁盤上對(duì)應(yīng)一個(gè)文件夾,分區(qū)命名規(guī)則為主題名稱后接“—”連接符,之后再接分區(qū)編號(hào),分區(qū)編號(hào)從0開始至分區(qū)總數(shù)減-1;
(4)LogSegment:每個(gè)分區(qū)又被劃分為多個(gè)日志分段(LogSegment)組成,日志段是Kafka日志對(duì)象分片的最小單位;LogSegment算是一個(gè)邏輯概念,對(duì)應(yīng)一個(gè)具體的日志文件(“.log”的數(shù)據(jù)文件)和兩個(gè)索引文件(“.index”和“.timeindex”,分別表示偏移量索引文件和消息時(shí)間戳索引文件)組成;
(5)Offset:每個(gè)partition中都由一系列有序的、不可變的消息組成,這些消息被順序地追加到partition中。每個(gè)消息都有一個(gè)連續(xù)的序列號(hào)稱之為offset—偏移量,用于在partition內(nèi)唯一標(biāo)識(shí)消息(并不表示消息在磁盤上的物理位置);
(6)Message:消息是Kafka中存儲(chǔ)的最小最基本的單位,即為一個(gè)commit log,由一個(gè)固定長(zhǎng)度的消息頭和一個(gè)可變長(zhǎng)度的消息體組成;
Kafka中的消息是以主題(Topic)為基本單位進(jìn)行組織的,各個(gè)主題之間相互獨(dú)立。在這里主題只是一個(gè)邏輯上的抽象概念,而在實(shí)際數(shù)據(jù)文件的存儲(chǔ)中,Kafka中的消息存儲(chǔ)在物理上是以一個(gè)或多個(gè)分區(qū)(Partition)構(gòu)成,每個(gè)分區(qū)對(duì)應(yīng)本地磁盤上的一個(gè)文件夾,每個(gè)文件夾內(nèi)包含了日志索引文件(“.index”和“.timeindex”)和日志數(shù)據(jù)文件(“.log”)兩部分。分區(qū)數(shù)量可以在創(chuàng)建主題時(shí)指定,也可以在創(chuàng)建Topic后進(jìn)行修改。(ps:Topic的Partition數(shù)量只能增加而不能減少,這點(diǎn)內(nèi)容超出本篇幅的減少范圍,大家可以先思考下)。
在Kafka中正是因?yàn)槭褂昧朔謪^(qū)(Partition)的設(shè)計(jì)模型,通過將主題(Topic)的消息打散到多個(gè)分區(qū),并分布保存在不同的Kafka Broker節(jié)點(diǎn)上實(shí)現(xiàn)了消息處理的高吞吐量。其生產(chǎn)者和消費(fèi)者都可以多線程地并行操作,而每個(gè)線程處理的是一個(gè)分區(qū)的數(shù)據(jù)。
同時(shí),Kafka為了實(shí)現(xiàn)集群的高可用性,在每個(gè)Partition中可以設(shè)置有一個(gè)或者多個(gè)副本(Replica),分區(qū)的副本分布在不同的Broker節(jié)點(diǎn)上。同時(shí),從副本中會(huì)選出一個(gè)副本作為L(zhǎng)eader,Leader副本負(fù)責(zé)與客戶端進(jìn)行讀寫操作。而其他副本作為Follower會(huì)從Leader副本上進(jìn)行數(shù)據(jù)同步。
創(chuàng)建3副本的topic
./kafka-topics.sh --create --zookeeper 10.154.0.73:2181 --replication-factor 3 --partitions 3 --topic kafka-topic-01
./kafka-topics.sh --describe --zookeeper 10.154.0.73:2181 --topic kafka-topic-01
每個(gè)分區(qū)在物理上對(duì)應(yīng)一個(gè)文件夾,分區(qū)的命名規(guī)則為主題名后接“—”連接符,之后再接分區(qū)編號(hào),分區(qū)編號(hào)從0開始,編號(hào)的大值為分區(qū)總數(shù)減1。每個(gè)分區(qū)又有1至多個(gè)副本,分區(qū)的副本分布在集群的不同代理上,以提高可用性。從存儲(chǔ)的角度上來(lái)說(shuō),分區(qū)的每個(gè)副本在邏輯上可以抽象為一個(gè)日志(Log)對(duì)象,即分區(qū)副本與日志對(duì)象是相對(duì)應(yīng)的。下圖是在三個(gè)Kafka Broker節(jié)點(diǎn)所組成的集群中分區(qū)的主/備份副本的物理分布情況圖:
在Kafka中,每個(gè)Log對(duì)象又可以劃分為多個(gè)LogSegment文件,每個(gè)LogSegment文件包括一個(gè)日志數(shù)據(jù)文件和兩個(gè)索引文件(偏移量索引文件和消息時(shí)間戳索引文件)。其中,每個(gè)LogSegment中的日志數(shù)據(jù)文件大小均相等(該日志數(shù)據(jù)文件的大小可以通過在Kafka Broker的config/server.properties配置文件的中的“l(fā)og.segment.bytes”進(jìn)行設(shè)置,默認(rèn)為1G大小(1073741824字節(jié)),在順序?qū)懭胂r(shí)如果超出該設(shè)定的閾值,將會(huì)創(chuàng)建一組新的日志數(shù)據(jù)和索引文件)。
Kafka將日志文件封裝成一個(gè)FileMessageSet對(duì)象,將偏移量索引文件和消息時(shí)間戳索引文件分別封裝成OffsetIndex和TimerIndex對(duì)象。Log和LogSegment均為邏輯概念,Log是對(duì)副本在Broker上存儲(chǔ)文件的抽象,而LogSegment是對(duì)副本存儲(chǔ)下每個(gè)日志分段的抽象,日志與索引文件才與磁盤上的物理存儲(chǔ)相對(duì)應(yīng);下圖為Kafka日志存儲(chǔ)結(jié)構(gòu)中的對(duì)象之間的對(duì)應(yīng)關(guān)系圖:
為了進(jìn)一步查看“.index”偏移量索引文件、“.timeindex”時(shí)間戳索引文件和“.log”日志數(shù)據(jù)文件,可以執(zhí)行下面的命令將二進(jìn)制分段的索引和日志數(shù)據(jù)文件內(nèi)容轉(zhuǎn)換為字符型文件:
# 1、執(zhí)行下面命令即可將日志數(shù)據(jù)文件內(nèi)容dump出來(lái)
./kafka-run-class.sh kafka.tools.DumpLogSegments --files /apps/svr/Kafka/kafkalogs/kafka-topic-01-0/00000000000022372103.log --print-data-log > 00000000000022372103_txt.log
#2、dump出來(lái)的具體日志數(shù)據(jù)內(nèi)容
Dumping /apps/svr/Kafka/kafkalogs/kafka-topic-01-0/00000000000022372103.log
Starting offset: 22372103
offset: 22372103 position: 0 CreateTime: 1532433067157 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 5d2697c5-d04a-4018-941d-881ac72ed9fd
offset: 22372104 position: 0 CreateTime: 1532433067159 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 0ecaae7d-aba5-4dd5-90df-597c8b426b47
offset: 22372105 position: 0 CreateTime: 1532433067159 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 87709dd9-596b-4cf4-80fa-d1609d1f2087
......
......
offset: 22372444 position: 16365 CreateTime: 1532433067166 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 8d52ec65-88cf-4afd-adf1-e940ed9a8ff9
offset: 22372445 position: 16365 CreateTime: 1532433067168 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 5f5f6646-d0f5-4ad1-a257-4e3c38c74a92
offset: 22372446 position: 16365 CreateTime: 1532433067168 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 51dd1da4-053e-4507-9ef8-68ef09d18cca
offset: 22372447 position: 16365 CreateTime: 1532433067168 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 80d50a8e-0098-4748-8171-fd22d6af3c9b
......
......
offset: 22372785 position: 32730 CreateTime: 1532433067174 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: db80eb79-8250-42e2-ad26-1b6cfccb5c00
offset: 22372786 position: 32730 CreateTime: 1532433067176 isvalid: true keysize: 4 valuesize: 36 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] key: 1 payload: 51d95ab0-ab0d-4530-b1d1-05eeb9a6ff00
......
......
#3、同樣地,dump出來(lái)的具體偏移量索引內(nèi)容
Dumping /apps/svr/Kafka/kafkalogs/kafka-topic-01-0/00000000000022372103.index
offset: 22372444 position: 16365
offset: 22372785 position: 32730
offset: 22373467 position: 65460
offset: 22373808 position: 81825
offset: 22374149 position: 98190
offset: 22374490 position: 114555
......
......
#4、dump出來(lái)的時(shí)間戳索引文件內(nèi)容
Dumping /apps/svr/Kafka/kafkalogs/kafka-topic-01-0/00000000000022372103.timeindex
timestamp: 1532433067174 offset: 22372784
timestamp: 1532433067191 offset: 22373466
timestamp: 1532433067206 offset: 22373807
timestamp: 1532433067214 offset: 22374148
timestamp: 1532433067222 offset: 22374489
timestamp: 1532433067230 offset: 22374830
......
......
由上面dump出來(lái)的偏移量索引文件和日志數(shù)據(jù)文件的具體內(nèi)容可以分析出來(lái),偏移量索引文件中存儲(chǔ)著大量的索引元數(shù)據(jù),日志數(shù)據(jù)文件中存儲(chǔ)著大量消息結(jié)構(gòu)中的各個(gè)字段內(nèi)容和消息體本身的值。索引文件中的元數(shù)據(jù)postion字段指向?qū)?yīng)日志數(shù)據(jù)文件中message的實(shí)際位置(即為物理偏移地址)。
下面的表格先列舉了Kakfa消息體結(jié)構(gòu)中幾個(gè)主要字段的說(shuō)明:
Kafka消息字段 | 各個(gè)字段說(shuō)明 |
---|---|
offset | 消息偏移量 |
message size | 消息總長(zhǎng)度 |
CRC32 | CRC32編碼校驗(yàn)和 |
attributes | 表示為獨(dú)立版本、或標(biāo)識(shí)壓縮類型、或編碼類型 |
magic | 表示本次發(fā)布Kafka服務(wù)程序協(xié)議版本號(hào) |
key length | 消息Key的長(zhǎng)度 |
key | 消息Key的實(shí)際數(shù)據(jù) |
valuesize | 消息的實(shí)際數(shù)據(jù)長(zhǎng)度 |
playload | 消息的實(shí)際數(shù)據(jù) |
從全文來(lái)看,Kafka高效數(shù)據(jù)存儲(chǔ)設(shè)計(jì)的特點(diǎn)在于以下幾點(diǎn):
(1)、Kafka把主題中一個(gè)分區(qū)劃分成多個(gè)分段的小文件段,通過多個(gè)小文件段,就容易根據(jù)偏移量查找消息、定期清除和刪除已經(jīng)消費(fèi)完成的數(shù)據(jù)文件,減少磁盤容量的占用;
(2)、采用稀疏索引存儲(chǔ)的方式構(gòu)建日志的偏移量索引文件,并將其映射至內(nèi)存中,提高查找消息的效率,同時(shí)減少磁盤IO操作;
(3)、Kafka將消息追加的操作邏輯變成為日志數(shù)據(jù)文件的順序?qū)懭耄瑯O大的提高了磁盤IO的性能;
任何一位使用Kafka的同學(xué)來(lái)說(shuō),如果能夠掌握其數(shù)據(jù)存儲(chǔ)機(jī)制,對(duì)于大規(guī)模Kafka集群的性能調(diào)優(yōu)和問題定位都大有裨益。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。