要深入学习Kafka,理解Kafka的存储机制是非常重要的。本文介绍Kafka存储消息的格式以及数据文件和索引组织方式,以便更好的理解Kafka是如何工作的。

Kafka消息存储格式

Kafka为了保证消息的可靠性,服务端会将接收的消息进行序列化并保存到磁盘上(Kafka的多副本存储机制),这里涉及到消息的存储格式,即消息编码后落到磁盘文件上的二进制的数据格式。下图是根据Kafka 3.0官方文档整理的消息格式:

包含三个部分:BatchRecords、Record,以及Header的编码格式。

BatchRecords是Kafka数据的存储单元,一个BatchRecords中包含多个Record(即我们通常说的一条消息)。BatchRecords中各个字段的含义如下:

字段名 含义
baseOffset 这批消息的起始Offset
partitionLeaderEpoch 用于Partition的Recover时保护数据的一致性,具体场景可以见KIP101
batchLength BatchRecords的长度
magic 魔数字段,可以用于拓展存储一些信息,当前3.0版本的magic是2
crc crc校验码,包含从attributes开始到BatchRecords结束的数据的校验码
attributes int16,其中bit0~2中包含了使用的压缩算法,bit3是timestampType,bit4表示是否失误,bit5表示是否是控制指令,bit6~15暂未使用
lastOffsetDelta BatchRecords中最后一个Offset,是相对baseOffset的值
firstTimestamp BatchRecords中最小的timestamp
maxTimestamp BatchRecords中最大的timestamp
producerId 发送端的唯一ID,用于做消息的幂等处理
producerEpoch 发送端的Epoch,用于做消息的幂等处理
baseSequence BatchRecords的序列号,用于做消息的幂等处理
records 具体的消息内容

一个BatchRecords中可以包含多条消息,即上图中的Record,而每条消息又可以包含多个Header信息,Header是Key-Value形式的。Record和Header的格式都非常简单,就不对其中的字段做解释了。

Log Segment

在Kafka中,一个Topic会被分割成多个Partition,而Partition由多个更小的,称作Segment的元素组成。

Kafka一个Partition下会包含类似上图中的一些文件,由log、index、timeindex三个文件组成一个Segment,而文件名中的(0和35)表示的是一个Segment的起始Offset(Kafka会根据log.segment.bytes的配置来决定单个Segment文件(log)的大小,当写入数据达到这个大小时就会创建新的Segment)。log、index、timeindex中存储的都是二进制的数据(log中存储的就是上一部分介绍的BatchRecords的内容,而index和timeindex分别是一些索引信息。)

下图是log文件中数据解析后的示意图(也就是本文第一部分BatchRecords格式)。其中16开头的这一行表示一个第一条消息的Offset是16的BatchRecord,而24开头的这一行表示的是一个第一条消息的Offset是24的BatchRecord。

索引

我们知道Kafka中每个Consumer消费一个Partition都会有一个关联的Offset表示已经处理过的消息的位置。通常Consumer会根据Offset连续的处理消息。而通过Offset从存储层中获取消息大致分为两步:

  • 第一步,根据Offset找到所属的Segment文件

  • 第二步,从Segment中获取对应Offset的消息数据

其中第一步可以直接根据Segment的文件名进行查找(上面已经介绍了Segment的文件面就是它包含的数据的起始Offset)。第二步则需要一些索引信息来快速定位目标数据在Segment中的位置,否则就要读取整个Segment文件了,这里需要的索引信息就是上面的index文件存储的内容。

index文件中存储的是Offset和Position(Offset对应的消息在log文件中的偏移量)的对应关系,这样当有Offset时可以快速定位到Position读取BatchRecord,然后再从BatchRecord中获取某一条消息。比如上述Offset25会被定位到24这个BatchRecord,然后再从这个BatchRecord中取出第二个Record(24这个BatchRecord包含了24、25两个Record)。

注意,Kafka并不会为每个Record都保存一个索引,而是根据log.index.interval.bytes等配置构建稀疏的索引信息。

除了index索引文件保存Offset和Position的映射关系外,Kafka中还维护了timeindex,保存了Timestamp和Offset的关系,用于应对一些场景需要根据timestamp来定位消息。timeindex中的一个(timestampX,offsetY)元素的含义是所有创建时间大于timestampX的消息的Offset都大于offsetY。

同样的,timeindex也采用了稀疏索引的机制,使用和index相同的配置(log.index.interval.bytes),所以timeindex和index是一一对应的。

总结

本文首先介绍了Kafka消息的存储格式,然后介绍了Kafka是如何索引(index & timeindex)存储的数据的。看完索引部分后遗留了一个疑问:每次读取消息都要先根据索引读取Position信息,然后再根据Position去读数据,而索引又是稀疏索引(查找索引也是要开销的),这样效率是否会比较低呢?如果利用Consumer总是顺序读取消息的特性,每次读取数据时都带上一些上下文信息(比如上一次Offset对应的Position信息)直接去读Log数据效率是否会更高?欢迎留言交流!

Kafka消息(存储)格式及索引组织方式的更多相关文章

  1. Kafka消息系统基础知识索引

    一些观念的修正 从 0.9 版本开始,Kafka 的标语已经从“一个高吞吐量,分布式的消息系统”改为"一个分布式流平台". Kafka不仅仅是一个队列,而且是一个存储,有超强的堆积 ...

  2. Kafka(3)--kafka消息的存储及Partition副本原理

    消息的存储原理: 消息的文件存储机制: 前面我们知道了一个 topic 的多个 partition 在物理磁盘上的保存路径,那么我们再来分析日志的存储方式.通过 [root@localhost ~]# ...

  3. Kafka消息文件存储

    在对消息进行存储和缓存时,Kafka依赖于文件系统.(Page Cache) 线性读取和写入是所有使用模式中最具可预计性的一种方式,因而操作系统采用预读(read-ahead)和后写(write-be ...

  4. 一文看懂Kafka消息格式的演变

    摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在不断的升级改进,从0.8.x版本开始到现在的1.1.x版本,Kaf ...

  5. 转载来自朱小厮博客的 一文看懂Kafka消息格式的演变

    转载来自朱小厮博客的 一文看懂Kafka消息格式的演变     ✎摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在 ...

  6. Kafka分片存储、消息分发和持久化机制

    Kafka 分片存储机制 Broker:消息中间件处理结点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka集群. Topic:一类消息,例如 page vi ...

  7. MyISAM的前缀压缩索引在索引块中的组织方式

    纯粹自己的理解,哪位大佬看到了还请指正. 首先贴一张<高性能MySQL>中的一段话: 这句话的意思是说,MyISAM使用b+树组织索引.也就是说无论索引压缩与否,组织方式一定是B+树. 下 ...

  8. 联合索引在B+树上的存储结构及数据查找方式

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 引言 上一篇文章<MySQL索引那些事>主要讲了MySQL索引的底层原理,且对比了B ...

  9. Kafka日志存储原理

    引言 Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相互独立的.每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建 ...

随机推荐

  1. Intel® QAT 加速卡之数据面流程(图)

    QAT数据面流程 sessionSetupData数据结构 pOpData数据结构

  2. netfilter框架之hook点

    1. Netfilter中hook的所在位置 当网络上有数据包到来时,由驱动程序将数据包从网卡内存区通过DMA转移到设备主存区(内存区), 之后触发中断通知CPU进行异步响应,之后ip_rcv函数会被 ...

  3. 一起学习PHP中GD库的使用(三)

    上篇文章我们已经学习了一个 GD 库的应用,那就是非常常用的制作验证码的功能.不过在现实的业务开发中,这种简单的验证码已经使用得不多了,大家会制作出更加复杂的验证码来使用.毕竟现在的各种外挂软件已经能 ...

  4. 解决下载的css样式文件在同一排的问题

    一.将样式文件里的所有内容复制到word里 Ctrl+F查找替换,将所有分号;替换成;^p 小提示:在word里^p表示回车 二.将央视文件里的所有反括号}进行替换替换成}^p然后将代码整个粘贴回样式 ...

  5. C# 将PPT转为OFD/DPT/DPS/ODP/POTX/UOP

    本文分享在C#代码程序中,如何将PPT幻灯片文档转换为多种文件格式,如:OFD.DPT.DPS.ODP.POTX.UOP等.只需在加载PPT幻灯片源文档后,调用ppt.SaveToFile(strin ...

  6. 深入HTML5第一天

    页面的title一般是30-40个字符:分别为主页,详情页,列表页  keywords:100个字符  description: em是:emphasize: 强调,着重  i:italic斜体的 : ...

  7. jmeter5.2版本 配置元件之参数化详解

    1.方式1 :CSV Data Set Config : 打开方式:配置元件---csv data set config 作用:用于读取txt.csv文件数据,注意:默认txt.csv文件的第一行内容 ...

  8. Jmeter集合点技术

    集合点简介 好比小学时候做广播体操,先让大家集合,等到时间统一开始做体操. 创建集合点 同步定时器 同时签到 注意:作用域 参数设置 用户数 为0 具体数值,不能大于 超时时间 为0,没有超时时间 具 ...

  9. 1.3redis小结--配置php reids拓展

    1.执行php文件 输出phpinfo();  <?php phpinfo(); 2.根据PHPinfo的信息确定需要下载的 php_redis.dll , php_igbinary.dll 版 ...

  10. GUI编程笔记

    GUI编程 告诉大家该怎么学? 这是什么? 它怎么玩? 该如何去我们平时运用? 组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 1.简介 GUi的核心技术:Sw ...