版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
相关概念
- topic 主题,特指kafka处理的消息源的不同分类
- partition topic物理上的分组,一个topic可以分为多个partition
- message 消息,是通信的基本单位
存储结构
topic结构
- topic包含多个partition,
- topic只是逻辑概念,不涉及到存储,partition才是物理概念
- 同一topic的不同partition可能分布在不同机器上
partition结构
- partition是一个文件夹,其中包含多个segment
- 如果其中有n个segment,则共有2*n个文件
- 每个partition是一个有序的队列
- partition中的每条消息都会分配一个有序的id,即offset
segment结构
- 由一对文件组成,一个索引文件,一个数据文件
- 文件命名规则
- 上一个segment在partition中的最大offset数值,即,比如00000000000000345678.log文件中的第一条消息的offset为345679
- 最大为64位的long,不足位数补0,如00000000000000345678.log
- 索引文件后缀.index,日志数据文件后缀.log
segment索引文件结构
- 存储一系列的元数据,每条元数据就是一条索引
- 元数据条数小于消息条数,是稀疏索引
- 元数据(即索引)构成
- 索引所指向的message在数据日志文件中的相对序号,即相对的offset,从1开始,该相对offset加上文件名当中的值就是该message在整个partition中的绝对offset了
- 索引所指向的message在数据日志文件中的位置,即文件游标,从0开始,方便直接指定游标打开数据文件
segment日志数据文件结构
- 存储一系列的message
message结构
- offset 偏移量,消息的唯一标识,通过offset能找到唯一消息,类型long 8bytes
- MessageSize 消息长度,类型int32 4bytes
- crc32校验码, 4bytes,校验message
- magic, 表示本次发布kafka服务程序协议版本号 1byte
- attributes 独立版本,标识压缩类型,编码类型 1byte
- key length 4bytes 当key length=-1时,key字段可不写
- key 可选
- payload 实际消息内容
message特点
- message是无状态的,即不会标识是否已被消费过
- message不能同时被多个consumer来消费,可以等前一个消费完成,下一个继续消费。
- consumer可以同时消费多条message
示例
partition的结构
可以发现,每对index和log就是一个segmentsegment索引文件结构
00000000000000345678.index
1,0
3,248
7,1347
...
N, 278597
- 1
- 2
- 3
- 4
- 5
- 6
- 7
对应的segment日志数据文件结构
00000000000000345678.log Message345679,起始位置: 0 Message345680,起始位置: Message345679的MessageSize字段 (该消息没有索引) Message345681,起始位置: Message345679的MessageSize字段 + Message345680的MessageSize字段 = 248 Message345682,起始位置: 248 + Message345681的MessageSize字段 (也没索引,可以看到直到第7条消息才重新有了索引) ...
- 1
- 2
- 3
- 4
- 5
- 6
查找流程
- 可以利用offset在partition中查找
- 不能在整个topic中查找的,因为offset只保证在partition中唯一,有序
- 流程如下(以查找offset为345683的message为例):
- 二分查找确认segment为00000000000000345678.index和00000000000000345678.log
- 在segment的index文件中, 345683-345678=5 ,接着再次二分查找所有元数据中offset小于等于该offset的值中最大的那个。即,小于等于5的所有数中最大的那一个,找到了(3,248)
- 打开00000000000000345678.log,直接移动文件指针到248,即读到了offset为345681的消息
- 顺序开始读取消息,直到读到offset为345683的message
存储结构设计原因
- 为什么有segment,而不是把partition直接设计成单个文件?
- 方便消费后删除,可以节约空间,如果是单个文件,该文件由于会被不断写入,无法删除,则会无限增加。当需要清理时,则需要在保证写入的同时,清理该文件的前面已经过期的消息,效率十分低下。
- 为什么有partition?
- 方便水平扩展broker,如果不设计多个partition,那么当部署完成之时,topic就会被限定在一台机器上了,随着业务增加,最终会陷入瓶颈
- 索引文件的作用
- 使查找效率为O(1),即与文件大小无关,与查找的位置无关