首先我们要知道Kafka本质上使用Java NIO的ByteBuffer来保存消息。
好处:ByteBuffer是紧凑的二进制字节结构,不浪费空间。
1.消息版本变迁
1.1V0版本
Kafka在0.10.0版本之前都是采用V0版本的消息格式
如下表格所示为V0版本的一条Record的组成及其含义:
Record | -字段- | -含义- |
---|---|---|
Record head | CRC校验码 | 4个字节CRC校验码,校验范围为magic到value之间,用于确保消息再传输过程中不会被恶意篡改 |
Record head | magic字段 | 单字节的版本号,V0 magic = 0 ,V1 magic =1 ,v2 magic =2 |
Record head | attribute | 单个字节属性字段,目前仅仅使用后三位来表示消息传输的压缩类型。 0x00: 未启用压缩 ,0x01: GZIP ,0x02: Snappy ,0x03: LZ4 |
Record head | key长度字段 | 4字节的消息key长度信息。若为指定key,默认值为-1 |
Record body | key值 | 消息key,长度由key长度字段确定,如果为-1,则没有该消息字段 |
Record head | value长度字段 | 4字节的消息长度,未指定 默认值为-1 |
Record body | value字段 | 消息value 长度由value长度字段确定 -1,消息没有该字段 |
可以计算出V0版本的一条Record最少需要14B的存储空间
1.2 V1版本消息格式
V0版本消息格式弊端:
- 1.消息不存储时间的话,kafka定期删除消息日志的时候,只能依靠日志段文件的“最近修改时间”,但是这种方式事不安全的,一旦我们通过系统的命令操作了文件,并且更新了该日志文件的最近修改时间,kakfa就不能对其做成正确的判断了。
- 2.很多流处理框架都需要消息的保存时间以便对消息执行时间窗口等聚合操作。
因此V1版本的消息格式比V0版本的消息格式多了一个timestamp字段。
timestamp:8个字节,记录了消息的时间戳。时间戳有两种创建类型,由attribute的第四个bit位决定的。
-
0:CreateTime (由Producer指定)
-
1:LogAppendTime(由Broker指定)
MessageSet(V0,V1 未开启压缩)
V0版本和V1版本Kafka处理消息都是以MesssageSet为基础的,分为压缩和未压缩两种格式
未开启消息压缩的传输格式:V0版本和V1版本都是一样的只是差了一个时间戳的字段。
如图所示为未开启压缩 的消息在Messag Set 中的一条Log都是以 Log OVERHEAD + Record为基础的