Kafka消息格式

从0.8.x版本开始到现在的2.x版本,Kafka的消息格式也经历了 3 个版本: v0 版本、v1 版本和 v2 版本 。

v0版本

Kafka 从 0.8.x 版本开始到 0.10.x 版本之前的消息格式通常称为 v0 版本。

下图中左边的 “RECORD” 部分就是 v0 版本的消息格式,每个 RECORD ( v0 和 v1 版)必定对应一个 offset 和 message size。offset 用来标志它在 Partition 中的偏移量 ,这个 offset 是逻辑值,而非实际物理偏移值,message size 表示消息的大小,这两者在一起被称为日志头部 (LOG_OVERHEAD ) ,固定为12B 。LOG_OVERHEAD 和 RECORD 一起用来描述一条消息
与消息对应的还有消息集的概念(详细结构参考下图中的右边部分),消息集中包含一条或多条消息,消息集不仅是存储于磁盘及在网络上传输(Produce & Fetch)的基本形式,而且是 Kafka 中压缩的基本单元

  • crc32 (4B):crc32 校验值 。校验范围为 magic 至 value 之间。
  • magic (1B):消息格式版本号,此版本的 magic 值为 0。
  • attributes (1B):消息的属性。总共占 1 个字节,低 3 位表示压缩类型:0 表示 NONE、1 表示 GZIP、2 表示 SNAPPY、3 表示 LZ4 (LZ4 自 Kafka 0.9.x 引入),其余位保留。
  • key length (4B):表示消息的 key 的长度。如果为 -1,则表示没有设置 key ,即 key= null。
  • key:可选,如果没有 key 则无此字段。
  • value length (4B): 实际消息体的长度。如果为 -1,则表示消息为空。
  • value:消息体。可以为空,比如墓碑(tombstone)消息。

v0版本中一个消息的最小长度(RECORD_OVERHEAD_V0)为crc32+magic+attributes+keylength+value length=4B+1B+1B+4B+4B=14B。也就是说,v0版本中一条消息的最小长度为14B,如果小于这个值,那么这就是一条破损的消息而不被接收。

2.0.0 版本之前如果想要查看日志分段文件中的内容,使用 “ kafka-run-class.sh kafka.tools.DumpLogSegments --files 文件名 ” 的方式。

v1版本

Kafka 从 0.10.0 版本开始到 0.11.0 版本之前所使用的消息格式版本为 v1,比 v0 版本就多了一个 timestamp 字段,表示消息的时间戳。 v1 版本的消息结构如下图所示。

v1版本的 magic 字段的值为1。
v1版本的 attributes 字段中的低3位和v0版本的一样,还是表示压缩类型,而第4个位(bit)也被利用了起来:0表示 timestamp 类型为 CreateTime,而1表示 timestamp 类型为 LogAppendTime,其他位保留。timestamp类型由broker端参数log.message.timestamp.type来配置,默认值为CreateTime,即采用生产者创建消息时的时间戳。如果在创建 ProducerRecord 时没有显式指定消息的时间戳,那么 KafkaProducer 也会在发送这条消息前自动添加上。

v1 版本的消息的最小长度(RECORD_OVERHEAD_V1)要比 v0 版本的大 8 个字节,即22B。

消息压缩

Kafka实现的压缩方式是将多条消息一起进行压缩,这样可以保证较好的压缩效果。

在一般情况下,生产者发送的压缩数据在broker中也是保持压缩状态进行存储的,消费者从服务端获取的也是压缩的消息,消费者在处理消息之前才会解压消息,这样保持了端到端的压缩。

Kafka 通过 broker 端参数 compression.type (生产者客户端的 compression.type 参数优先级更高)来配置日志中使用哪种压缩方式,默认值为“producer”,表示保留生产者使用的压缩方式。这个参数还可以配置为"gzip"、"snappy"、"lz4",分别对应 GZIP、SNAPPY、LZ4 这 3 种压缩算法。如果参数 compression.type 配置为“uncompressed”,则表示不压缩。

压缩率是压缩后的大小与压缩前的对比。例如:把100MB的文件压缩后是90MB,压缩率为90/100×100%=90%,压缩率越小,压缩效果越好。

当消息压缩时是将整个消息集进行压缩作为内层消息(inner message),内层消息整体作为外层(wrapper message)的 value,其结构如下图所示。压缩后的外层消息(wrapper message)中的 key 为 null,所以下图左半部分没有画出key字段,value字段中保存的是多条压缩消息(inner message,内层消息),其中Record表示的是从 crc32 到 value 的消息格式。

当生产者创建压缩消息的时候,对内部压缩消息设置的 offset 从 0 开始为每个内部消息分配 offset,详细可以参考下图右半部分。其实每个从生产者发出的消息集中的消息offset都是从0开始的,当然这个offset不能直接存储在日志文件中,对 offset 的转换是在服务端进行的,客户端不需要做这个工作。外层消息保存了内层消息中最后一条消息的绝对位移(absolute offset),绝对位移是相对于整个分区而言的。参考下图,对于未压缩的情形,图右内层消息中最后一条的offset理应是1030,但被压缩之后就变成了5,而这个1030被赋予给了外层的 offset。

v1版本比v0版的消息多了一个timestamp字段。对于压缩的情形,外层消息的timestamp设置为:

  • 如果timestamp类型是CreateTime,那么设置的是内层消息中最大的时间戳。
  • 如果timestamp类型是LogAppendTime,那么设置的是Kafka服务器当前的时间戳。

内层消息的timestamp设置为:

  • 如果外层消息的timestamp类型是CreateTime,那么设置的是生产者创建消息时的时间戳。
  • 如果外层消息的timestamp类型是LogAppendTime,那么所有内层消息的时间戳都会被忽略。

对 attributes 字段而言,它的 timestamp 位只在外层消息中设置,内层消息中的timestamp类型一直都是CreateTime。

v2版本

Kafka 从 0.11.0 版本开始所使用的消息格式版本为 v2,这个版本的消息相比 v0 和 v1 的版本而言改动很大,同时还参考了 Protocol Buffer而引入了变长整型(Varints)和ZigZag编码。

……

2.0.0版本开始如果想要查看日志分段文件中的内容,使用 “ kafka-dump-log.sh --files 文件名 ” 的方式。

2.x版本前后两种查看日志分段的方式在本质上没有什么区别,只不过在Kafka 2.0.0之前并没有kafka-dump-log.sh脚本,所以只能使用kafka-run-class.sh kafka.tools.DumpLogSegments的形式,而从Kafka 2.0.0开始,可以直接使用kafka-dump-log.sh脚本来避免书写错误。通过查看kafka-dump-log.sh脚本可以发现,内部还是使用kafka-run-class.sh kafka.tools.DumpLogSegments的方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值