什么是 kafka segment
为了更加方便管理 kafka Replication 中的数据,kafka 将一个 Replication 拆分成多个大小相等的数据段,这每一小段数据被 kafka 称为 segment
每个 segment 文件的大小相等,但消息数量不一定相等,这种特性方便已经被消费的消息的清理,提高磁盘的利用率
segment 的组成
一个 segment 对应磁盘上多个文件
- *.index : 消息的 offset 索引文件
- *.timeindex : 消息的时间索引文件(0.8版本加入的)
- *.log : 消息的数据
可能还会有
- *.snapshot : 记录了 producer 的事务信息。(todo)
- *.swap : 用于 Segment 恢复。(todo)
- *.txnindex文件,记录了中断的事务信息。(todo)
这里重点讲前三个
文件的命名
segment 的文件命名采用该 segment 中第一条消息的 offset,长度为19位,不足的前面补 0
partion 的全局第一个 segment 序号从 0 开始,后续每个 segment 文件名为上一个 segment 文件最后一条消息的 offset 值加一
offset 的最大值为 Long.MAX_VALUE = 2的63次方-1,这也是一个 segment 能存储消息的最大条数,超出就需要分多个 segment 存储,当然,由于 kafka 限制了 segment 的大小,所以基本不会出现这样的情况
kafka 稀疏索引
想要查询速度的快,为数据添加索引是个常用的方法, kafka 也不例外,但不同的是 kafka 使用的是稀疏索引
常见的索引一般是保存数据集中每条记录的部分字段,例如关系型数据库中的索引都是这种。但稀疏索引不会为每条记录都建索引,而是隔一段建一条,因此被称为稀疏索引
稀疏索引最大的好处是节约了磁盘空间,但代价是,查找速度不如普通索引,因为你只能找到一个大致的区间,想要找到具体的记录,就需要遍历区间的数据,相当于拿时间换空间
由于 kafka 设计为循序读写磁盘,因此遍历区间的数据并对速度有太大的影响,而选择稀疏索引还能节约大量的磁盘空间。
kafka 对稀疏索引的运用
kafka 为消息数据建了两种稀疏索引,一种是方便 offset 查找的 .index 稀疏索引,还有一种是方便时间查找的 .timeindex 稀疏索引
segment 各文件的文件内容
通过 kafka 自带的工具,可以查看 .log 等文件的内容
kafka安装目录/bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files ./xxx.log
复制代码
打开一个 .index 文件,可以看到内容类似如下
offset: 53 position: 4124
offset: 106 position: 8264
...
offset: 1302 position: 103050
offset: 1354 position: 107210
复制代码
- offset : 消息的偏移量
- position : 消息在磁盘上的物理地址
.timeindex 文件内容类似如下
timestamp: 1547557706588 offset: 53
timestamp: 1547557707588 offset: 106
...
timestamp: 1547557716601 offset: 1302
timestamp: 1547557717179 offset: 1354
复制代码
- timestamp : 消息的时间戳
- offset : 消息的偏移量
.log 文件内容类似如下
offset: 1301 position: 102970 CreateTime: 1547557716588 payload: message_1301
offset: 1302 position: 103050 CreateTime: 1547557716601 payload: message_1302
offset: 1303 position: 103130 CreateTime: 1547557716612 payload: message_1303
offset: 1304 position: 103210 CreateTime: 1547557716624 payload: message_1304
...
offset: 1353 position: 107130 CreateTime: 1547557717167 payload: message_1353
offset: 1354 position: 107210 CreateTime: 1547557717179 payload: message_1354
offset: 1355 position: 107290 CreateTime: 1547557717183 payload: message_1355
复制代码
上面的消息内容,不同的版本可能有些差异,但核心不会变
稀疏索引查找过程
以 .index 文件为例,例如我要查看 offset 为 1365 的消息
首先,既然是通过 offset 查找数据,我们就可以遍历该 topic 下所有的分区,查看 1365 在哪个分区,找到后,在遍历该分区所有的 .index 文件名,找到 1365 在哪个文件中,之后读取该文件的内容,找到 1365 所在的区间,以上图为例,1365 在 1250-1500 这个区间里面,因此从 1250 的 position 10897 处开始循序读取硬盘,直到找到 offset 为 1365 这条消息
.timeindex 文件同理,只不过它的查找结果是 offset,之后还要在走一遍 .index 索引
segment 的配置
server.properties
中 segment 相关配置如下
# 分段文件的大小
log.segment.bytes=107370
## 保留时长,默认7天,到期会自动清理
log.retention.hours=168
# 保留的数据大小,最大只会保留这么多的数据,超过这个大小,会清理旧数据
log.retention.bytes=1073741824
复制代码
kafka 读取速度快的原因
kafka 通过以下 5 个层面,实现了时间复杂度为 O(1) 的读取速度
topic 分类 -> 消息分区(partition) -> 数据分块(segment) -> 间隙索引 -> 顺序读写