面试记录 2026-09-22
题目:Kafka 的消息的结构是什么样的
难度:low
标签:db/mq/kafka, mq/kafka, general/knowledge, difficulty/low
评分:⭐⭐☆☆☆(2/5)
我的回答
Kafka 消息体的结构,这块我没有太大印象,但是基础应该包含内容我能想不到。首先必须要有唯一的 ID,明确这个 Kafka 的消息的消息具体是什么信息,是什么位置啊。然后其实就是偏移量,如何读取这条数据。然后是大小,这个消息大概有多大。然后是消息体,消息内容。暂时我能想到的一个消息的基本结构应该就是这个样子的,可能还会包括,应该还会包括 topic,就是标,具体归属于哪个主题。
点评
优点:
- 抓住了 offset(位置定位)和 size(大小)、message body(消息体)这几个基础直觉
不足:
- 把 offset 说成"唯一的 ID",概念混淆:offset 只在单 partition 内唯一,全局并不唯一
- 完全没有提到 Key——这是 Kafka 消息结构里最重要的字段之一,决定消息落到哪个 partition(hash(key) % numPartitions)
- 遗漏 Timestamp、Headers(0.11 引入)、Magic Value(版本号)、CRC 校验
- 把 Topic 当成消息内部字段,其实 Topic 属于 Partition 层的组织概念,不在单条 Message 里
补充:
- Kafka 消息结构经历过演进:0.10 之前用 MessageSet(每条消息独立压缩头),0.11 起用 RecordBatch(按批次压缩,含 baseOffset + offsetDelta),效率提升明显
- 生产实际中,Key 通常用作"同一订单/用户/设备的消息路由到同一 partition"以保证顺序性,是理解 Kafka 并发模型的关键
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对 Kafka 底层消息存储格式的掌握,判断是否真正理解 Kafka 的消息如何被写入磁盘、如何被压缩、如何被消费者正确解析。
知识点拆解:
- 两代消息格式:
- Legacy MessageSet(Magic 0/1,Kafka 0.10 之前):每条 Message 独立结构,压缩粒度小
- RecordBatch(Magic 2,Kafka 0.11+):一个批次打包多条 Record,整批 CRC + 整批压缩,性能和压缩率都大幅提升
- 单条 Record 的字段(Magic 2):
attributes(压缩类型、isDeleted)
length(key 长度)、key(分区路由键)
length(value 长度)、value(消息体)
numHeaders + headers(键值对,用户自定义元数据)
timestamp、offsetDelta(相对 baseOffset 的偏移)
- RecordBatch 头部字段:
baseOffset、batchLength、partitionLeaderEpoch
magicValue(版本号,2)
crc(32 位,覆盖除自身外的所有字节)
attributes、lastOffsetDelta、firstOffsetDelta
numRecords、记录集合
从「单条消息」演进到「批次消息」,是 Kafka 追求吞吐与压缩率的直接体现。
第二部分:考察方向与延伸递进
考察方向:
- 深度:Magic value 版本演进、CRC 覆盖范围、isDeleted 逻辑删除位、压缩粒度对性能的影响
- 广度:与 RocketMQ 消息头对比、与 Avro/Protobuf Schema 注册的关系(Headers 可携带 Schema ID)
- 应用:如何在消费端做 Exactly-Once、如何基于 Key 实现分区顺序、如何用 Headers 做链路追踪
延伸递进面试题:
- Kafka 0.11 之后为什么把消息格式从 MessageSet 改成 RecordBatch?
- 解答要点:批量压缩减少 CPU 开销、baseOffset 让单条消息体更紧凑、支持按批读放大(zero-copy)
- 消息的 Key 是 null 和 Key="" 的区别是什么?
- 解答要点:null 走粘性分区(sticky partitioner),"" 走 hash 路由到固定分区
- 如果消息体超过 max.message.bytes 会怎么样?
- 解答要点:producer 端直接抛异常,不会截断,需要调 producer 和 broker 两端配置
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,Kafka 的消息结构其实经历过一次比较大的演进。0.10 之前用的是 MessageSet,一条消息就是一个独立的结构;从 0.11 开始改成了 RecordBatch,一个批次打包多条 Record,这样做的好处是压缩和 CRC 都按批次做,性能和压缩率都上去了。
单条 Record 里最重要的字段有几个:第一个是 Key,这个是消息路由到哪个 Partition 的依据,同一 Key 一定落同一分区,用来保证同一业务实体的顺序;第二个是 Value,也就是消息体;然后是 Headers,0.11 引入的键值对,可以放用户自定义的元数据,比如链路追踪的 traceId;再就是 Timestamp,用来做数据保留和消息压缩的策略;还有 offsetDelta,是相对 baseOffset 的偏移量。
RecordBatch 头部有 baseOffset,代表这一批起始的偏移;CRC 用来校验整批数据;partitionLeaderEpoch 用来感知 Leader 切换。
所以真正理解 Kafka 消息结构,关键有两点:一是 Key 决定路由和顺序;二是 0.11 之后从单条消息演进到批次消息,是为了批量压缩和零拷贝读放大,这也是 Kafka 高吞吐的底层原因之一。
面试记录 2026-10-12(第 2 次)
题目:Kafka 的消息的结构是什么样的
难度:low
标签:db/mq/kafka, mq/kafka, difficulty/low
评分:⭐⭐⭐☆☆(3/5)
练习次数:2
我的回答
Kafka 消息结构,首先要有消息体、消息头两部分。消息头中要有 topic、partition,确定具体消费的内容,消息在哪。还有消息的 ID 还有偏移量。消息体中要有消息的信息,具体消息内容是什么?理解主要有这些内容。另外应该还有状态,消息的消费状态。
点评
优点:
- 意识到消息由"头 + 体"两部分组成,这个直觉是对的
- 想到了 offset,能感知到 Kafka 是"位点定位"模型
- 想到了"消费状态"这个概念(虽不属于消息本身,但说明你在想端到端)
不足:
- Key 完全没提——这是最致命的遗漏,Key 决定消息路由到哪个 partition,是理解 Kafka 顺序性、并行度、粘性分区的核心
- 把 Topic、Partition 说成"消息头里的字段"——其实它们属于分区层组织概念,不在单条 Message 结构里
- "消息 ID" 概念模糊,Kafka 单条消息没有 ID 字段,唯一标识是
(topic, partition, offset) 三元组
- 漏了 Timestamp(做数据保留和按时间压缩)、Headers(0.11 引入,可放 traceId 等元数据)
补充:
- 消费状态(consumer offset)不属于消息本身,而是消费者组自己维护的元数据,存在
__consumer_offsets 内部 topic
- 0.11+ 的 RecordBatch 把多条消息打包,用
baseOffset + offsetDelta 表示每条位置,比 0.10 的 MessageSet 压缩率更好
ℹ️ 完整讲解见上方首次记录(2026-09-22)
面试记录 2026-10-25(第 3 次)
练习次数:3
评分:⭐⭐⭐☆☆(3/5)
我的回答
Kafka 消息结构主要有两部分——消息头和消息体。由于 Kafka 是批量发送,消息体是批量并压缩后的消息数组。消息头记录开始偏移量、开始时间戳、偏移量总长度、最后偏移量、CRC 校验码、消息数等信息。消息内部是压缩后的消息数组,每个消息也有自己的消息头和消息内容,以及 key 等。
点评
优点:
- 抓到批量+压缩的核心思想
- 识别出 Batch 头 + Record 头两级结构
- 提到 Key 字段
不足:
- 字段名不精确,漏 magic=2(RecordBatch 版本标识)
- 漏 baseOffset / lastOffsetDelta / numRecords 具体字段
- 漏 producerId/epoch/baseSequence(幂等+事务基础)
- 漏 attributes(含压缩 codec 位)
补充:
- offsetDelta/timestampDelta 是相对偏移(不是绝对值),这是 RecordBatch 相比 MessageSet 省空间的核心——每条 record 不用重复存完整 offset/timestamp。Key 是路由和顺序性的关键,null Key 在 3.x 走 sticky partitioner。