轉(zhuǎn)載來(lái)自朱小廝博客的 一文看懂Kafka消息格式的演變

轉(zhuǎn)載來(lái)自朱小廝博客的 一文看懂Kafka消息格式的演變

?摘要

對(duì)于一個(gè)成熟的消息中間件而言,消息格式不僅關(guān)系到功能維度的擴(kuò)展,還牽涉到性能維度的優(yōu)化。隨著Kafka的迅猛發(fā)展,其消息格式也在不斷的升級(jí)改進(jìn),從0.8.x版本開始到現(xiàn)在的1.1.x版本,Kafka的消息格式也經(jīng)歷了3個(gè)版本。本文這里主要來(lái)講述Kafka的三個(gè)版本的消息格式的演變,文章偏長(zhǎng),建議先關(guān)注后鑒定。

Kafka根據(jù)topic(主題)對(duì)消息進(jìn)行分類,發(fā)布到Kafka集群的每條消息都需要指定一個(gè)topic,每個(gè)topic將被分為多個(gè)partition(分區(qū))。每個(gè)partition在存儲(chǔ)層面是追加log(日志)文件,任何發(fā)布到此partition的消息都會(huì)被追加到log文件的尾部,每條消息在文件中的位置稱為offset(偏移量),offset為一個(gè)long型的數(shù)值,它唯一標(biāo)記一條消息。

每一條消息被發(fā)送到Kafka中,其會(huì)根據(jù)一定的規(guī)則選擇被存儲(chǔ)到哪一個(gè)partition中。如果規(guī)則設(shè)置的合理,所有的消息可以均勻分布到不同的partition里,這樣就實(shí)現(xiàn)了水平擴(kuò)展。如上圖,每個(gè)partition由其上附著的每一條消息組成,如果消息格式設(shè)計(jì)的不夠精煉,那么其功能和性能都會(huì)大打折扣。比如有冗余字段,勢(shì)必會(huì)使得partition不必要的增大,進(jìn)而不僅使得存儲(chǔ)的開銷變大、網(wǎng)絡(luò)傳輸?shù)拈_銷變大,也會(huì)使得Kafka的性能下降;又比如缺少字段,在最初的Kafka消息版本中沒(méi)有timestamp字段,對(duì)內(nèi)部而言,其影響了日志保存、切分策略,對(duì)外部而言,其影響了消息審計(jì)、端到端延遲等功能的擴(kuò)展,雖然可以在消息體內(nèi)部添加一個(gè)時(shí)間戳,但是解析變長(zhǎng)的消息體會(huì)帶來(lái)額外的開銷,而存儲(chǔ)在消息體(參考下圖中的value字段)前面可以通過(guò)指針偏量獲取其值而容易解析,進(jìn)而減少了開銷(可以查看v1版本),雖然相比于沒(méi)有timestamp字段的開銷會(huì)差一點(diǎn)。如此分析,僅在一個(gè)字段的一增一減之間就有這么多門道,那么Kafka具體是怎么做的呢?本文只針對(duì)Kafka 0.8.x版本開始做相應(yīng)說(shuō)明,對(duì)于之前的版本不做陳述。

v0版本

對(duì)于Kafka消息格式的第一個(gè)版本,我們把它稱之為v0,在Kafka 0.10.0版本之前都是采用的這個(gè)消息格式。注意如無(wú)特殊說(shuō)明,我們只討論消息未壓縮的情形。

在具體講述v0版的消息(Record)格式之前,我們先來(lái)了解下消息集(Message Set)的概念。消息包含鍵值對(duì)(key/value)和一些元數(shù)據(jù)(crc32、magic、attributes),而消息集是包含offset、message size以及一系列消息的集合。消息集不僅是存儲(chǔ)于磁盤以及在網(wǎng)絡(luò)上傳輸?shù)幕拘问剑沂莐afka中壓縮的基本單元。v0版的消息集結(jié)構(gòu)如下圖所示:

每條消息都一個(gè)offset用來(lái)標(biāo)志它在partition中的偏移量,這個(gè)offset是邏輯值,而非實(shí)際物理偏移值。在未壓縮的情況下,對(duì)于v0和v1版本而言,每個(gè)消息集中只包含一條消息,消息集中的offset也是消息的offset(壓縮的情況有所不同,下面會(huì)介紹)。大多數(shù)人會(huì)把上圖的全部?jī)?nèi)容看成是消息的格式,這里需要注意Record和Message Set的區(qū)別。message size表示消息集中的消息大小。offset和message size總體表示為消息集的日志頭部(LOG_OVERHEAD),總大小固定為12B。

而消息(Record)格式是從crc32開始算起中各個(gè)字段的解釋如下:

crc32(4B):crc32校驗(yàn)值。校驗(yàn)范圍為magic至value之間。

magic(1B):消息格式版本號(hào),此版本的magic值為0。

attributes(1B):消息的屬性??偣舱?個(gè)字節(jié),低3位表示壓縮類型:0表示NONE、1表示GZIP、2表示SNAPPY、3表示LZ4(LZ4自Kafka 0.9.x引入),其余位保留。

key length(4B):表示消息的key的長(zhǎng)度。如果為-1,則表示沒(méi)有設(shè)置key,即key=null。

key:可選,如果沒(méi)有key則無(wú)此字段。

value length(4B):實(shí)際消息體的長(zhǎng)度。如果為-1,則表示消息為空。

value:消息體??梢詾榭眨热鐃omnstone消息。

由上圖我們也可以得知,v0版本中一個(gè)消息的最小長(zhǎng)度(RECORD_OVERHEAD_V0)為crc32 + magic + attributes + key length + value length = 4B + 1B + 1B + 4B + 4B =14B,也就是說(shuō)v0版本中一條消息的最小長(zhǎng)度為14B,如果小于這個(gè)值,那么這就是一條破損的消息而不被接受。

這里我們來(lái)做一個(gè)測(cè)試,首先創(chuàng)建一個(gè)partition數(shù)和副本數(shù)都為1的topic,名稱為“msg_format_v0”:

[root@node1 kafka_2.10-0.8.2.1]# bin/kafka-topics.sh --create

--zookeeper localhost:2181--topic msg_format_v0 --partitions1--replication-factor1

[root@node1 kafka_2.10-0.8.2.1]# bin/kafka-topics.sh --describe

--zookeeper localhost:2181--topic msg_format_v0

Topic:msg_format_v0 ? ?PartitionCount:1ReplicationFactor:1Configs:

Topic: msg_format_v0 ? ?Partition:0Leader:0Replicas:0Isr:0

然后往msg_format_v0中發(fā)送一條key="key",value="value"的消息,之后查看對(duì)應(yīng)的日志:

[root@node1 kafka_2.10-0.8.2.1]# bin/kafka-run-class.shkafka.tools.DumpLogSegments

--files /tmp/kafka-logs/msg_format_v0-0/00000000000000000000.log

Dumping /tmp/kafka-logs-08/msg_format_v0-0/00000000000000000000.log

Starting offset:0

offset:0position:0isvalid:truepayloadsize:5magic:0

compresscodec: NoCompressionCodec crc:592888119keysize:3

查看消息的大小,即00000000000000000000.log文件的大小為34B,其值正好等于LOG_OVERHEAD+RECORD_OVERHEAD_V0 + 3B的key + 5B的value = 12B + 14B + 3B + 5B = 34B。

[root@node1 msg_format_v0-0]#ll*.log

-rw-r--r--1rootroot34Apr26 02:5200000000000000000000.log

我們?cè)侔l(fā)送一條key=null, value="value"的消息,之后查看日志的大?。?/p>

[root@node3 msg_format_v0-0]#ll*.log

-rw-r--r--1rootroot65Apr26 02:5600000000000000000000.log

日志大小為65B,減去上一條34B的消息,可以得知本條消息的大小為31B,正好等于LOG_OVERHEAD+RECORD_OVERHEAD_V0 + 5B的value = 12B + 14B+ 5B = 31B。

消息壓縮

壓縮率是壓縮后的大小與壓縮前的對(duì)比。例如:把100MB的文件壓縮后是90MB,壓縮率為90 / 100 * 100% =90%,壓縮率一般是越小壓縮效果越好。常見(jiàn)的壓縮算法是數(shù)據(jù)量越大壓縮率越低,一條消息通常不會(huì)太大,這就導(dǎo)致壓縮率比較高,壓縮效果不太好。而kafka實(shí)現(xiàn)的壓縮方式是將多條消息一起進(jìn)行壓縮,這樣可以保證較高的壓縮效果。而且在一般情況下,生產(chǎn)者發(fā)送的壓縮數(shù)據(jù)在kafka broker中也是保持壓縮狀態(tài)進(jìn)行存儲(chǔ),消費(fèi)者從服務(wù)端獲取也是壓縮的消息,消費(fèi)者在處理消息之前才會(huì)解壓消息,這樣保持了端到端的壓縮。

壓縮后的消息格式與非壓縮的消息格式類似,但是分為內(nèi)外兩層,參考下圖:

壓縮后的外層消息(wrapper message)中的key為null,所以圖左部分沒(méi)有畫出key這一部分,value字段中保存的是多條壓縮消息(inner message, 內(nèi)層消息),其中Record表示的是從crc32到value的消息格式。當(dāng)生產(chǎn)者創(chuàng)建壓縮消息的時(shí)候,對(duì)內(nèi)部壓縮消息設(shè)置的offset是從0開始為每個(gè)內(nèi)部消息分配offset,詳細(xì)可以參考下圖右部:

kafka broker在為外層消息分配offset的時(shí)候,會(huì)根據(jù)外層消息中記錄的內(nèi)層消息的個(gè)數(shù)為外層消息分配offset,此offset的值是內(nèi)層消息中最后一條消息原本的offset值。參考上圖,對(duì)于未壓縮的情形,圖右內(nèi)層消息最后一條的offset理應(yīng)是1030,但是被壓縮之后就變成了5,而這個(gè)1030被賦予給了外層的offset。這種壓縮的情形下,如果要找到內(nèi)層消息集合的起始移位,首先要解壓縮內(nèi)層,然后遍歷每一條消息,然后才能推到出起始位移,代價(jià)昂貴。

v1版本

kafka從0.10.0版本開始到0.11.0版本之前所使用的消息格式版本為v1,其比v0版本就多了一個(gè)timestamp字段,表示消息的時(shí)間戳。v1版本的結(jié)構(gòu)圖如下所示:

v1版本的magic字段值為1。v1版本的attributes字段中的低3位和v0版本的一樣,還是表示壓縮類型,而第4個(gè)bit也被利用了起來(lái):0表示timestamp類型為CreateTime,而1表示tImestamp類型為L(zhǎng)ogAppendTime,其他位保留。v1版本的最小消息(RECORD_OVERHEAD_V1)大小要比v0版本的要大8個(gè)字節(jié),即22B。如果像v0版本介紹的一樣發(fā)送一條key="key",value="value"的消息,那么此條消息在v1版本中會(huì)占用42B,具體測(cè)試步驟參考v0版的相關(guān)介紹。

Varints

kafka從0.11.0版本開始所使用的消息格式版本為v2,這個(gè)版本的消息相比于v0和v1的版本而言改動(dòng)很大,同時(shí)還參考了Protocol Buffer而引入了變長(zhǎng)整型(Varints)和ZigZag編碼。為了更加形象的說(shuō)明問(wèn)題,首先我們來(lái)了解一下變長(zhǎng)整型。

Varints是使用一個(gè)或多個(gè)字節(jié)來(lái)序列化整數(shù)的一種方法。數(shù)值越小,其所占用的字節(jié)數(shù)就越少。Varints中每個(gè)字節(jié)都有一個(gè)位于最高位的msb位(most significant bit),除了最后一個(gè)字節(jié)外其余msb位都設(shè)置為1,最后一個(gè)字節(jié)的msb位設(shè)置為0。這個(gè)msb位表示其后的字節(jié)是否和當(dāng)前字節(jié)一起來(lái)表示同一個(gè)整數(shù)。除msb位之外,剩余的7位用于存儲(chǔ)數(shù)據(jù)本身,這種表示類型又稱之為Base 128。通常而言,一個(gè)字節(jié)8位可以表示256個(gè)值,所以稱之為Base 256,而這里只能用7位表示,2的7次方即為128。Varints中采用小端字節(jié)序,即最小的字節(jié)放在最前面。

舉個(gè)例子,比如數(shù)字1,它只占一個(gè)字節(jié),所以msb位為0:

0000 0001

再舉一個(gè)復(fù)雜點(diǎn)的例子,如數(shù)字300:

1010 1100 0000 0010

300的二進(jìn)制表示原本為:0000 0001 0010 1100 = 256+32+8+4=300,那么為什么300的變長(zhǎng)表示為上面的這種形式?

首先我們先去掉每個(gè)字節(jié)的msb位,表示如下:

1010 1100 0000 0010

-> 010 1100 000 0010

如前所述,varints是小端字節(jié)序的布局方式,所以這里兩個(gè)字節(jié)的位置需要翻轉(zhuǎn)一下:

010 1100 000 0010

-> 000 0010 010 1100 (翻轉(zhuǎn))

-> 000 0010 ++ 010 1100

-> 0000 0001 0010 1100 = 256+32+8+4=300

Varints可以用來(lái)表示int32、int64、uint32、uint64、sint32、sint64、bool、enum等類型。在實(shí)際使用過(guò)程中,如果當(dāng)前字段可以表示為負(fù)數(shù),那么對(duì)于int32/int64和sint32/sint64而言,它們?cè)谶M(jìn)行編碼時(shí)存在著較大的區(qū)別。比如你使用int64表示一個(gè)負(fù)數(shù),那么哪怕是-1,其編碼后的長(zhǎng)度始終為10個(gè)字節(jié)(可以通過(guò)下面的代碼來(lái)測(cè)試長(zhǎng)度),就如同對(duì)待一個(gè)很大的無(wú)符號(hào)長(zhǎng)整型一樣。為了使得編碼更加的高效,Varints使用了ZigZag的編碼方式。

publicintsizeOfLong(intv){

intbytes =1;

while((v &0xffffffffffffff80L) !=0L) {

bytes +=1;

v >>>=7;

}

returnbytes;

}

ZigZag編碼以一種鋸齒形(zig-zags)的方式來(lái)回穿梭于正負(fù)整數(shù)之間,以使得帶符號(hào)整數(shù)映射為無(wú)符號(hào)整數(shù),這樣可以使得絕對(duì)值較小的負(fù)數(shù)仍然享有較小的Varints編碼值,比如-1編碼為1,1編碼為2,-2編碼為3,參考下表:

原值編碼后的值

00

-11

12

-23

21474836474294967294

-21474836484294967295

對(duì)應(yīng)的公式為:

(n <<1) ^ (n>> 31)

這是對(duì)于sint32而言的,sint64對(duì)應(yīng)的公式為:

(n <<1) ^ (n>> 63)

以-1為例,其二進(jìn)制表現(xiàn)形式為:1111 1111 1111 1111 1111 1111 1111 1111(補(bǔ)碼)。

(n <<1) ?=11111111111111111111111111111110

(n>> 31) =00000000000000000000000000000001

(n <<1) ^ (n>> 31) =1

最終-1的Varints編碼為0000 0001,這樣原本用4字節(jié)表示的-1現(xiàn)在可以用1個(gè)字節(jié)來(lái)表示了。對(duì)于1而言就顯得非常簡(jiǎn)單了,其二進(jìn)制表現(xiàn)形式為:0000 0000 0000 0000 0000 0000 0000 0001。

(n <<1) ?=00000000000000000000000000000010

(n>> 31) =00000000000000000000000000000000

(n <<1) ^ (n>> 31) =2

最終1的Varints編碼為0000 0010,也只占用一個(gè)字節(jié)。

前面說(shuō)過(guò)Varints中的一個(gè)字節(jié)中只有7位是有效數(shù)值位,即只能表示128個(gè)數(shù)值,轉(zhuǎn)變成絕對(duì)值之后其實(shí)質(zhì)上只能表示64個(gè)數(shù)值。比如對(duì)于消息體長(zhǎng)度而言,其值肯定是個(gè)大于等于0的正整數(shù),那么一個(gè)字節(jié)長(zhǎng)度的Varints最大只能表示63(從0開始計(jì))。對(duì)于64而言,其二進(jìn)制表示為:

0100 0000

經(jīng)過(guò)ZigZag處理后為:

1000 0000 ^ 0000 0000 = 1000 0000

每個(gè)字節(jié)的低7位是有效數(shù)值位,所以1000 0000進(jìn)一步轉(zhuǎn)變?yōu)椋?/p>

000 0001 000 0000

而Varints又是小端字節(jié)序,所以需要翻轉(zhuǎn)一下位置:

000 0000 000 0001

設(shè)置非最后一個(gè)字節(jié)的msb位為1,最后一個(gè)字節(jié)的msb位為0,最終有:

1000 0000 0000 0001

所以最終64表示為:1000 0000 0000 0001,而63卻表示為:0111 1110。

回顧一下kafka v0和v1版本的消息格式,如果消息本身沒(méi)有key,那么key length字段為-1,int類型的需要4個(gè)字節(jié)來(lái)保存,而如果采用Varints來(lái)編碼則只需要一個(gè)字節(jié)。根據(jù)Varints的規(guī)則可以推導(dǎo)出0-63之間的數(shù)字占1個(gè)字節(jié),64-8191之間的數(shù)字占2個(gè)字節(jié),8192-1048575之間的數(shù)字占3個(gè)字節(jié)。而kafka broker的配置message.max.bytes的默認(rèn)大小為1000012(Varints編碼占3個(gè)字節(jié)),如果消息格式中與長(zhǎng)度有關(guān)的字段采用Varints的編碼的話,絕大多數(shù)情況下都會(huì)節(jié)省空間,而v2版本的消息格式也正是這樣做的。

不過(guò)需要注意的是Varints并非一直會(huì)省空間,一個(gè)int32最長(zhǎng)會(huì)占用5個(gè)字節(jié)(大于默認(rèn)的4字節(jié)),一個(gè)int64最長(zhǎng)會(huì)占用10字節(jié)(大于默認(rèn)的8字節(jié))。下面代碼展示如何計(jì)算一個(gè)int32占用的字節(jié)個(gè)數(shù):

publicstaticintsizeOfVarint(intvalue){

intv = (value<<1) ^ (value>>31);

intbytes =1;

while((v &0xffffff80) !=0L) {

bytes +=1;

v >>>=7;

}

returnbytes;

}

v2版本

消息集從Message Set的代號(hào)轉(zhuǎn)變成為Record Batch(參見(jiàn)下圖),其中包含了1至多條消息(Record,參見(jiàn)下圖中部和右部)。在消息壓縮的情形下,Record Batch Header部分(參見(jiàn)下圖左部,從first offset到records count字段)是不被壓縮的,而被壓縮的是records字段。

先來(lái)講述一下消息格式Record的關(guān)鍵字段,可以看到內(nèi)部字段大量采用了Varints,這樣Kafka可以根據(jù)具體的值來(lái)確定需要幾個(gè)字節(jié)來(lái)保存。v2版本的消息格式去掉了crc字段,另外增加了length(消息總長(zhǎng)度)、timestamp delta(時(shí)間戳增量)、offset delta(位移增量)和headers信息,并且attributes被棄用了,筆者對(duì)此做如下分析(對(duì)于key、key length、value、value length字段和v0以及v1版本的一樣,這里不再贅述):

length:消息總長(zhǎng)度。

attributes:棄用,但是還是在消息格式中占據(jù)1B的大小,以備未來(lái)的格式擴(kuò)展。

timestamp delta:時(shí)間戳增量。通常一個(gè)timestamp需要占用8個(gè)字節(jié),如果像這里保存與RecordBatch的其實(shí)時(shí)間戳的差值的話可以進(jìn)一步的節(jié)省占用的字節(jié)數(shù)。

offset delta:位移增量。保存與RecordBatch起始位移的差值,可以節(jié)省占用的字節(jié)數(shù)。

headers:這個(gè)字段用來(lái)支持應(yīng)用級(jí)別的擴(kuò)展,而不需要像v0和v1版本一樣不得不將一些應(yīng)用級(jí)別的屬性值嵌入在消息體里面。Header的格式如上圖最有,包含key和value,一個(gè)Record里面可以包含0至多個(gè)Header。具體可以參考以下KIP-82。

如果對(duì)于v1版本的消息,如果用戶指定的timestamp類型是LogAppendTime而不是CreateTime,那么消息從發(fā)送端(Producer)進(jìn)入broker端之后timestamp字段會(huì)被更新,那么此時(shí)消息的crc值將會(huì)被重新計(jì)算,而此值在Producer端已經(jīng)被計(jì)算過(guò)一次;再者,broker端在進(jìn)行消息格式轉(zhuǎn)換時(shí)(比如v1版轉(zhuǎn)成v0版的消息格式)也會(huì)重新計(jì)算crc的值。在這些類似的情況下,消息從發(fā)送端到消費(fèi)端(Consumer)之間流動(dòng)時(shí),crc的值是變動(dòng)的,需要計(jì)算兩次crc的值,所以這個(gè)字段的設(shè)計(jì)在v0和v1版本中顯得比較雞肋。在v2版本中將crc的字段從Record中轉(zhuǎn)移到了RecordBatch中。

v2版本對(duì)于消息集(RecordBatch)做了徹底的修改,參考上圖左部,除了剛剛提及的crc字段,還多了如下字段:

first offset:表示當(dāng)前RecordBatch的起始位移。

length:計(jì)算partition leader epoch到headers之間的長(zhǎng)度。

partition leader epoch:用來(lái)確保數(shù)據(jù)可靠性,詳細(xì)可以參考KIP-101。

magic:消息格式的版本號(hào),對(duì)于v2版本而言,magic等于2。

attributes:消息屬性,注意這里占用了兩個(gè)字節(jié)。低3位表示壓縮格式,可以參考v0和v1;第4位表示時(shí)間戳類型;第5位表示此RecordBatch是否處于事務(wù)中,0表示非事務(wù),1表示事務(wù)。第6位表示是否是Control消息,0表示非Control消息,而1表示是Control消息,Control消息用來(lái)支持事務(wù)功能。

last offset delta:RecordBatch中最后一個(gè)Record的offset與first offset的差值。主要被broker用來(lái)確認(rèn)RecordBatch中Records的組裝正確性。

first timestamp:RecordBatch中第一條Record的時(shí)間戳。

max timestamp:RecordBatch中最大的時(shí)間戳,一般情況下是指最后一個(gè)Record的時(shí)間戳,和last offset delta的作用一樣,用來(lái)確保消息組裝的正確性。

producer id:用來(lái)支持冪等性,詳細(xì)可以參考KIP-98。

producer epoch:和producer id一樣,用來(lái)支持冪等性。

first sequence:和producer id、producer epoch一樣,用來(lái)支持冪等性。

records count:RecordBatch中Record的個(gè)數(shù)。

這里我們?cè)賮?lái)做一個(gè)測(cè)試,在1.0.0的kafka中創(chuàng)建一個(gè)partition數(shù)和副本數(shù)都為1的topic,名稱為“msg_format_v2”。然后同樣插入一條key="key",value="value"的消息,查看日志結(jié)果如下:

[root@node1 kafka_2.12-1.0.0]# bin/kafka-run-class.shkafka.tools.DumpLogSegments

--files /tmp/kafka-logs/msg_format_v2-0/00000000000000000000.log --print-data-log

Dumping /tmp/kafka-logs/msg_format_v2-0/00000000000000000000.log

Starting offset:0

baseOffset:0lastOffset:0baseSequence:-1lastSequence:-1producerId:-1

producerEpoch:-1partitionLeaderEpoch:0isTransactional:falseposition:0

CreateTime:1524709879130isvalid:truesize:76magic:2compresscodec: NONE

crc:2857248333

可以看到size字段為76,我們根據(jù)上圖中的v2版本的日志格式來(lái)驗(yàn)證一下,Record Batch Header部分共61B。Record部分中attributes占1B;timestamp delta值為0,占1B;offset delta值為0,占1B;key length值為3,占1B,key占3B;value length值為5,占1B,value占5B;headers count值為0,占1B, 無(wú)headers。Record部分的總長(zhǎng)度=1B+1B+1B+1B+3B+1B+5B+1B=14B,所以Record的length字段值為14,編碼為變長(zhǎng)整型占1B。最后推到出這條消息的占用字節(jié)數(shù)=61B+14B+1B=76B,符合測(cè)試結(jié)果。同樣再發(fā)一條key=null,value="value"的消息的話,可以計(jì)算出這條消息占73B。

這么看上去好像v2版本的消息比之前版本的消息占用空間要大很多,的確對(duì)于單條消息而言是這樣的,如果我們連續(xù)往msg_format_v2中再發(fā)送10條value長(zhǎng)度為6,key為null的消息,可以得到:

baseOffset: 2 lastOffset: 11 baseSequence: -1 lastSequence: -1 producerId: -1

producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false position: 149

CreateTime: 1524712213771 isvalid: true size: 191 magic: 2 compresscodec: NONE

crc: 820363253

本來(lái)應(yīng)該占用740B大小的空間,實(shí)際上只占用了191B,如果在v0版本中這10條消息則需要占用320B的空間(v1版本則需要占用400B的空間),這樣看來(lái)v2版本又節(jié)省了很多的空間,因?yàn)槠鋵⒍鄠€(gè)消息(Record)打包存放到單個(gè)RecordBatch中,又通過(guò)Varints編碼極大的節(jié)省了空間。

有興趣的同學(xué)可以自行測(cè)試一下在大批量消息的情況下,v2版本的消息占用大小和之前版本的對(duì)比,比如往msg_format_v0和msg_format_v2中各自發(fā)送100W條1KB的消息。具體的測(cè)試報(bào)告會(huì)在后面的文章中發(fā)出,但通過(guò)上面的陳述可知v2版本的消息不僅提供了更多的功能,比如事務(wù)、冪等性等,某些情況下還減少了消息的空間占用,總體提升很大。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容