Kafka-之数据日志存储(格式变化与压缩)

Kafka-之数据日志存储

1 kafka的日志布局

kafka的数据存储是基于文件系统的,kafka的数据以日志的形式存储在磁盘上,具体的日志布局可以看下图。

在这里插入图片描述

很明显,kafka以topic来进行数据划分,我们可以通过在server.properties文件指定log.dirs来指定数据日志存储

#指定日志存储路径
log.dirs=/tmp/kafka-logs1,tmp/kafka-logs2,....

虽说kafka按照topic进行数据划分,但是在物理存储上还是按照topic-partition进行目录划分,假如这里有个topicA有2个partition,那么它的存储结构如下:

cd /tmp/kafka-logs1/
		topicA-0/
				#在每个分区下的数据又是按日志分段进行存储的,每个日志分段LogSegment都有自己的索引文件和辅助文件
        00000000000000000000.index # offset索引文件
        00000000000000000000.log	 # 实际数据日志	
        00000000000000000000.timeindex  # 时间戳索引文件			
        00000000000000000000.txnindex   # unknown
        00000000000000000000.snapshot   # 快照记录文件

    topicA-1/
    		.............

kafka的消息都是顺序写入磁盘的logSegment文件的,只有最后一个logSegment文件才能执行写入操作,在其之前的所有xxx.log都不能写入,通常我们将最后一个LogSegment称为activeSegment,之后追加的消息将写入activeSegment,当其大小达到一定程度时就会重新生成一个新的activeSegment的.log文件。

为了方便日志分段文件检索,每个LogSegment都有对应的标识(baseoffset)和索引文件。

  • .index(offset索引文件,用来检索offset)
  • .timeindex(时间戳索引,用来检索时间戳)
  • baseoffset(该值代表每个segment文件的数据的起始offset,如00000000000000133.log,那么该分段的起始offset是133,如果上一个分段文件为00000000000000000.log,那么上个分段文件中存储了133条消息)

还可能出现.delete,.cleaned,.swap,.txnindex,leader_ecpoch_checkpoint等文件。

从更加宏观的角度来讲,kafka的日志目录结构如下:

在这里插入图片描述

2 kafka日志格式演变

从kafka-0.8x到目前的2.x版本已经经历了3个大版本V0,V1,V2

  • V0:0.8x-0.10.0,不包括0.10.0
  • V1:0.10.0到0.11.0版本之前,不包括0.11.0
  • V2:0.11.0到如今

2.1 V0的消息格式

在这里插入图片描述

上图左边的就是V0版本的Record格式,通常通过LOG_OVERHEADRECORD_OVERHEAD同时来描述一个消息,右边的Message Set是消息容器,用于存储消息。

  • crc32: crc32校验值,作用范围magic~value之间 (4B
  • magic: 消息版本号,这里是0 (1B
  • attributes:消息属性,0-3代表压缩格式(1B
    • 0代表NONE
    • 1代表GZIP
    • 2代表SNAPPY
    • 3代表LZO4(0.9x引入)
  • key length代表key的长度(4B),如果为-1,代表key为null,是没有设置key的
  • key代表消息的key
  • value length代表value的长度(4B
  • value代表消息

在V0版本中消息的最小长度为 4 + 1 + 1 + 4 + 4 = 14B(byte),如果小于这个值那么,那么这个消息就是一条破损的消息而不被接收,我们可以使用kafka内部的工具类查看置顶的segment文件的RECORD_OVERHEAD_V0(消息的最小值)信息

./kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/topic1-0/00000000000033568928.log 

>>>>>>
#这里将会显示starting offset、offset、position、isvalid、payloadsize、magic、compressCodec、crc、keysize信息,当前演示版本为kafka-0.8.2.1
Starting offset : 33568928
offset: 33568928 position : 0 isvalid: true payloadsize: 5 magic: 0 
compresscodec: NoCompressionCodec crc: 592888119 keysize : 3

2.2 V1的消息格式

在这里插入图片描述

除了新引入了一个timestamp,magic=1,其它的都是与V0相同,timestamp的大小为8B,所以V1版本的最小消息(RECORD_OVERHEAD_V1)为14+8=22B(byte)。

  • 该timestamp字段由broker端的参数log.message.timestamp.type指定,默认是生产者创建消息的时间createTime;
  • 我们可以通过在创建ProducerRecord的时候进行指定,new ProducerRecord(,timestamp);
  • 如果没有显式手动指定timestamp,那么就会选择time.milliseconds();
  • V1与V0一样,都是通过LOG_OVERHEADRECORD_OVERHEAD来描述一个message。

2.3 V2的消息格式

V2版本的消息集从Message Set变成了Record Batch,这是一个处理批量消息读写的NIO 通道channel,在消息压缩的过中,Record Batch Header部分是不会被压缩的(也就是下图中first offset到records count部分),被压缩的是records字段中的所有内容,每个Records中包含一条或多条Record。

  • Record Batch对应Producer client中的Producerbatch
  • Record对应Producer Record中的ProducerRecord

在这里插入图片描述
V2版本的Record格式去除了crc,将其移动到了RECORDBATCH,另外增加了length、timestamp delta 、offset delta;key、key length、value、value length还是与V0,V1保持一致,具体的新增的字段如下。

  • length:消息的总长度;
  • attributes:字段在V2中虽然没被使用,但是任然为其保留1B的空间,保证可扩展;
  • timestamp delta:时间戳增量,是当前消息的时间戳与RecordBatch的起始时间戳的差值,通常存储一个时间戳需要8个字节,这里存储的差值进一步减少了存储的消耗;
  • offset delta:位移增量,如果数据条目特别多,那么存储offset也是需要较多的存储,这里存储的是当前消息的offset与RecordBatch起始offset的差值,进一步节省存储空间;
  • headers:用来存储应用级别的扩展。

除了对RECORD本身做了修改,在V2版本还对RECORDBATCH进行了彻底的修改,除了对上面的crc校验,同时还新增了如下字段。

  • first offset:这个RECORBATCH的起始位移
  • length:从partition leader epoch字段到末尾的总长度,并不是消息的总长度
  • partition leader epoch:可以看作leader的版本号,或者看作分区leader的更新次数
  • magic: 消息格式的版本号
  • attributes:消息属性,0~3位依旧是压缩类型
  • last offset delta :RECORDBATCH中的最后一个RECORD的offset与first offset的差值(增量)
  • first timestamp:第一条消息的时间戳
  • producer id:生产者id:PID,用来与first sequence一起保证单个生产者-分区-单个session的幂等性
  • producer epoch:与producer id一样,用来支持事物与幂等(递增序列)
  • first sequence:与producer id,producer epoch一样,用来保证事物与幂等(递增序列)
  • records count:该RECORDBATCH中RECORD的条目数

2.4 消息压缩

消息越多压缩的效果越明显,数据比较少的时候选择压缩反而不太好,通常kafka的消息在生产者这里就开始选择压缩,在Broker上也是以压缩的形式进行存储的,只有在消费数据处理数据的术后才会将消息进行解压,这样就保证了端到端的压缩。在kafka的参数中,压缩格式通过compress.type来指定,默认为producer,表示保留生产者使用的压缩方式,还可以选择lz4,snappy,gzip等配置,分别表示使用LZ4,SNAPPY,GZIP的压缩算法

注:压缩率 = 压缩后大小 /压缩前大小 * 100%,压缩率通常是越小越好,而口语中常说压缩率越高越好。

kafka中有 2个概念,不能混淆

  • compress message 使用压缩算法将消息进行压缩,减少内存,网络io,与磁盘的消耗
  • compact message 将日志中的消息进行清理,类似于hbase的compact操作

在这里插入图片描述
消息的压缩是针对整个消息集RECORDBATCH(MESSAGE SET),将整个消息集压缩成wrapper message 和inner message,如下图

该途中offset为RECORDBATCH的first offset,内层消息中的offset为每个 record的offset与外层offset的增量,即(x - first offset)。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值