kafka日志格式

248 阅读4分钟

Apache Kafka 的日志格式是其高效存储和快速检索消息的核心设计之一。Kafka 的消息以二进制形式按顺序追加到日志文件中,其格式设计兼顾了存储效率、序列化速度和扩展性。


1. 日志文件的物理结构

Kafka 的日志文件由多个 日志段(Segment) 组成,每个段包含以下文件:

  • 数据文件(.log :存储实际的消息数据。
  • 位移索引文件(.index :记录消息位移(Offset)到物理位置的映射。
  • 时间戳索引文件(.timeindex :记录时间戳到消息位移的映射。

每个日志段以基准位移(Base Offset)命名,例如 00000000000000000000.log,表示该段的第一条消息的 Offset。


2. 单条消息的存储格式

Kafka 的消息格式分为多个版本(V0、V1、V2),不同版本在存储细节上有所优化。以下是 V2 版本(推荐使用) 的详细结构:

(1) 消息的二进制格式

+------------------------------------------------------------------------------------------------+
| Record Batch                                                                                  |
| +------------------------+ +---------------------+ +---------------------------------------+ |
| | Batch Header           | | Record 1            | | Record 2            | ... | Record N | |
| +------------------------+ +---------------------+ +---------------------------------------+ |
+------------------------------------------------------------------------------------------------+

(2) 消息批次头(Batch Header)

批次头描述了一组消息的元信息,适用于批量写入的场景:

字段大小(字节)说明
Base Offset8当前批次第一条消息的基准位移。
Batch Length4整个批次的总长度(包括 Header 和所有 Records)。
Partition Leader Epoch4Leader 的任期标识,用于防止数据不一致。
Magic1格式版本标识符(V2 对应值为 2)。
CRC324校验和,验证批次完整性。
Attributes2控制位(如压缩类型、时间戳类型)。
Last Offset Delta4批次中最后一条消息的位移相对于 Base Offset 的差值。
First Timestamp8批次中第一条消息的时间戳(支持 CreateTime 或 LogAppendTime)。
Max Timestamp8批次中最大的时间戳。
Producer ID8生产者 ID(用于事务支持)。
Producer Epoch2生产者的任期 ID(用于事务支持)。
Base Sequence4生产者发送消息的起始序列号(用于事务支持)。
Records Count4批次中包含的消息条数。

(3) 单条消息(Record)的格式

+--------------------------------------+
| Record Header                        |
| +----------------+ +---------------+ |
| | Header Key     | | Header Value | |
| +----------------+ +---------------+ |
+--------------------------------------+
| Key Length (变长) | Key (可选)        |
+--------------------------------------+
| Value Length (变长) | Value (可选)    |
+--------------------------------------+
字段大小(字节)说明
Length变长(Varint)当前 Record 的总长度。
Attributes1控制位(如是否启用压缩)。
Timestamp Delta变长(Varlong)时间戳相对于批次 First Timestamp 的差值。
Offset Delta变长(Varint)位移相对于批次 Base Offset 的差值。
Headers变长自定义键值对(用于扩展元数据,如 Trace ID)。
Key Length变长(Varint)Key 的长度(-1 表示 Key 为空)。
Key变长消息的 Key(可选)。
Value Length变长(Varint)Value 的长度(-1 表示 Value 为空)。
Value变长消息的 Value(实际负载数据)。

3. 消息格式的版本演进

版本引入版本核心改进
V0Kafka 0.10.0基础格式,无时间戳字段,每条消息独立存储。
V1Kafka 0.11.0增加时间戳字段,支持日志压缩(Log Compaction)和事务消息。
V2Kafka 2.1.0引入批量记录(Record Batch),减少冗余元数据存储;支持变长整数(Varint)编码,节省空间。

4. 消息格式的设计优势

  1. 批量写入优化

    • V2 版本将多条消息打包为 Record Batch,共享批次头信息(如时间戳、位移),减少重复元数据存储。
  2. 紧凑存储

    • 使用 Varint/Varlong 编码变长整数,减少小数值的存储空间。
  3. 扩展性

    • 支持 Headers 字段,可添加自定义元数据(如 Trace ID、路由信息)。
  4. 事务支持

    • V1 和 V2 版本通过 Producer IDProducer EpochBase Sequence 实现精确一次语义(Exactly-Once)。

5. 日志格式与索引文件的协同

  • 位移索引(.index : 存储 <Offset, 物理位置> 的映射,通过二分查找快速定位消息在 .log 文件中的位置。

  • 时间戳索引(.timeindex : 存储 <Timestamp, Offset> 的映射,支持按时间范围检索消息。

  • 查找流程

    1. 根据目标 Offset 或时间戳找到对应的日志段。
    2. 通过索引文件定位到 .log 文件的近似位置。
    3. 顺序扫描少量数据即可找到精确消息。

6. 示例:消息存储的物理布局

假设一个批次包含两条消息:

Record Batch Header:
  Base Offset: 100
  Records Count: 2
  First Timestamp: 1630000000000
​
Record 1:
  Key: "order-123"
  Value: "{"status": "shipped"}"
  Timestamp Delta: 0
  Offset Delta: 0
​
Record 2:
  Key: "order-456"
  Value: "{"status": "delivered"}"
  Timestamp Delta: 1000 (对应 First Timestamp + 1000ms)
  Offset Delta: 1 (对应 Base Offset + 1)

.log 文件中的二进制存储如下:

[Batch Header][Record1][Record2]

7. 配置参数

参数作用
log.message.format.version指定 Broker 使用的消息格式版本(如 2.1-IV2)。
compression.type设置消息压缩类型(如 snappygziplz4)。
message.timestamp.type定义时间戳类型(CreateTimeLogAppendTime)。

总结

Kafka 的日志格式通过 批量存储变长编码索引优化 实现了高吞吐量与低存储开销:

  • V2 格式 是当前最优选择,适合生产环境。
  • 索引文件 与日志段协同工作,保障快速检索。
  • 事务和压缩 等高级功能依赖特定格式版本,需合理配置。