Kafka Message 消息

Kafka 消息是指由生产者发送的一条记录,它在 Kafka 中以特定的格式进行存储。

Kafka 作为一个成熟的消息中间件,它的消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化。随着 Kafka 的迅猛发展,消息格式也在不断的升级改进。

Kafka 的消息格式也经历了3个版本:v0、v1 和 v2。

Kafka 的消息格式对于使用 Kafka 的开发人员是透明的。也就是说无论是使用生产者发送消息,还是使用消费者使用消息,都无需更关心。Kafka 提供了各种编程语言的 API。开发者只需要使用这些 API 发送和接收消息即可。

本章的内容,对于一般开发者只需要大体了解就可以了。资深开发者可以详细阅读,以便更好的使用和优化 Kafka 应用。

 

1. v0 版本

对于 Kafka 消息格式的第一个版本,我们把它称之为 v0,在Kafka 0.10.0版本之前都是采用的这个消息格式。存储格式如下:

左图中的 “RECORD” 部分就是 v0 版本的消息格式。但大多数人会把左图中的整体,即包括 offset 和 message size 字段都看成是消息,因为每个Record(v0和v1版)必定对应一个 offset 和 message size。

每条消息都一个 offset 用来标志它在 partition(Kafka分区,可以认为是一个普通文件)中的偏移量,这个 offset 是逻辑值,而非实际物理偏移值,message size表示消息的大小,这两者的一起被称之为日志头部(LOG_OVERHEAD),固定为 12B。

LOG_OVERHEAD 和 RECORD 一起用来描述一条消息。与消息对应的还有消息集的概念,消息集中包含一条或者多条消息,消息集不仅是存储于磁盘以及在网络上传输的基本形式。详细结构参考右图。

 

2. 消息格式字段含义

消息格式中从 crc32 开始算起,各个字段的解释如下:

  • 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:消息体。可以为空,比如tomnstone消息。

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

 

3. 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,其他位保留。v1 版本的最小消息(RECORD_OVERHEAD_V1)大小要比 v0 版本的要大8个字节,即22B。

 

4. 消息压缩

常见的压缩算法是数据量越大压缩效果越好,一条消息通常不会太大,这就导致压缩效果并不太好。而kafka实现的压缩方式是将多条消息一起进行压缩,这样可以保证较好的压缩效果。

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

消息压缩时是将整个消息集进行压缩而作为内层消息(inner message),内层消息整体作为外层(wrapper message)的 value,其结构图如下所示:

 

5. v2 版本

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

Varints 是使用一个或多个字节来序列化整数的一种方法,数值越小,其所占用的字节数就越少。ZigZag 编码以一种锯齿形(zig-zags)的方式来回穿梭于正负整数之间,以使得带符号整数映射为无符号整数,这样可以使得绝对值较小的负数仍然享有较小的 Varints 编码值,比如-1编码为1,1编码为2,-2编码为3。

v2 版本中消息集谓之为 Record Batch,而不是先前的 Message Set了,其内部也包含了一条或者多条消息,消息的格式参见下图中部和右部。在消息压缩的情形下,Record Batch Header 部分(参见下图左部,从first offset到records count字段)是不被压缩的,而被压缩的是 records 字段中的所有内容。

v2版本的消息不仅提供了类似事务、幂等等更多的功能,还对空间占用提供了足够的优化,总体提升很大。

生产者是向不同分区内的主题发布或写入数据的生产者。生产者自动知道应该将哪些数据写入哪个分区和代理。用户不需要指定代理和分区。生产者如何向集群写入数据?生产者使用以下策略向集群写入数据:Message ...