专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  昨天  
程序猿  ·  “我真的受够了Ubuntu!” ·  2 天前  
程序员的那些事  ·  成人玩偶 + ... ·  3 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

Kafka 文件存储机制

SegmentFault思否  · 公众号  · 程序员  · 2020-02-28 12:01

正文

本文转载于 SegmentFault 社区
作者:Gent



存储文件结构


topic :可以理解为一个消息队列的名字

partition :为了实现扩展性,一个非常大的 topic 可以分布到多个 broker (即服务器) 上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列

segment partition 物理上由多个 segment 组成

message 每个 segment 文件中实际存储的每一条数据就是 message

offset 每个 partition 都由一系列有序的、不可变的消息组成,这些消息被连续的追加到 partition 中,partition 中的每个消息都有一个连续的序列号叫做 offset,用于 partition 唯一标识一条消息




Partition 分区


本例中 topic 名称为 test-topic ,默认设置 partition 3 ,topic 创建成功后默认的存储位置在: /tmp/kafka-logs 下,分区分别以 topic 名称-分区数命名 (不考虑副本的情况) 如下:
//分布在不同的broker节点上
test-topic-0
test-topic-1
test-topic-2
疑问一: 为什么要分区呢?

为了性能考虑,如果不分区每个 topic 消息只存在一个 broker 上,那么所有的消费者都是从这个 broker 上消费消息,那么单节点的 broker 成为性能的瓶颈,如果有分区的话生产者发过来的消息分别存储在各个 broker 不同的 partition 上,这样消费者可以并行的从不同的 broker 不同的 partition 上读消息,实现了水平扩展。

疑问二: 分区文件下到底存了那些东西?

如下,其实每个分区下保存了很多文件,而概念上我们把他叫 segment ,即每个分区都是又多个 segment 构成的,其中 index (索引文件) ,log (数据文件) time index (时间索引文件) 统称为一个 segment
test-topic-0
├── 00000000000000000001.index
├── 00000000000000000001.log
├── 00000000000000000001.timeindex
├── 00000000000000001018.index
├── 00000000000000001018.log
├── 00000000000000001018.timeindex
├── 00000000000000002042.index
├── 00000000000000002042.log
├── 00000000000000002042.timeindex
疑问三: 为什么有了 partition 还需要 segment ?

通过上面目录显示存在多个 segment 的情况,既然有分区了还要存多个 segment 干嘛?如果不引入 segment ,那么一个 partition 只对应一个文件 (log) ,随着消息的不断发送这个文件不断增大,由于 kafka 的消息不会做更新操作都是顺序写入的,如果做消息清理的时候只能删除文件的前面部分删除,不符合 kafka 顺序写入的设计,如果多个 segment 的话那就比较方便了,直接删除整个文件即可保证了每个 segment 的顺序写入。


Segment 存储


Segment 中核心文件是 index 索引文件和 l og 数据文件,既然是索引文件当然是为了更高效的定位到数据,那么索引文件和数据文件中到底是存了那些数据? 又是如何快速找到消息数据呢?

3.1 使用 kafka 自带脚本发送测试数据


sh kafka-producer-perf-test.sh --topic test-topic --num-records 50000000 --record-size 1000 --throughput 10000000  --producer-props bootstrap.servers=192.168.60.201:9092

3.2 使用 kafka 自带脚本 Dump index

  
sh kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/test-topic-0/00000000000000001018.index --print-data-log
offset: 1049 position: 16205
offset: 1065 position: 32410
offset: 1081 position: 48615
offset: 1097 position: 64820
offset: 1113 position: 81025
offset: 1129 position: 97230
通过 dump index 我们发现其实索引文件中其实就保存了 offset position ,分别是消息的 offset 也就是具体那一条消息, position 表示具体消息存储在 log 中的物理地址。

疑问一: 通过上面数据可以看出,kafka 并不是每个 offset 都保存了,每隔 6 个 offset 存储一条索引数据,为什么在 index 文件中这些 offset 编号不是连续的呢?

因为 index 文件中并没有为数据文件中的每条消息都建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。但缺点是没有建立索引的 Message 也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。






请到「今天看啥」查看全文