partition
:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker
(即服务器)
上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列
segment
:
partition 物理上由多个 segment 组成
message
:
每个 segment 文件中实际存储的每一条数据就是 message
offset
:
每个 partition 都由一系列有序的、不可变的消息组成,这些消息被连续的追加到 partition 中,partition 中的每个消息都有一个连续的序列号叫做 offset,用于 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
中核心文件是
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
也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。