存储文件结构


topic

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

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

segment

: partition 物理上由多个 segment 组成

message

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

offset

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

kafka怎么查看分区 kafka查看分区文件在哪里_kafka


Partition 分区

 

本例中 topic 名称为 test-topic ,默认设置 partition 为 3 ,topic 创建成功后默认的存储位置在: /tmp/kafka-logs   下,分区分别以 topic 名称-分区数命名 , (不考虑副本的情况) 如下:

//分布在不同的broker节点上
test-topic-0  
test-topic-1  
test-topic-2
//分布在不同的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
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
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
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
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 也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。


3.3 使用 kafka 自带脚本 Dump log


  


sh kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/test-topic-0/00000000000000001018.log --print-data-log
sh kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/test-topic-0/00000000000000001018.log --print-data-log




kafka怎么查看分区 kafka查看分区文件在哪里_数据_02


log 数据文件中并不是直接存储数据,而是通过许多的 message 组成, message 包含了实际的消息数据   

kafka怎么查看分区 kafka查看分区文件在哪里_kafka怎么查看分区_03


  疑问一:消费者如何通过 offset 查找 message?

  

假如我们想要读取 offset=1066 的 message ,需要通过下面 2 个步骤查找。 (1)查找 segment file

00000000000000000000.index 表示最开始的文件,起始偏移量 (offset) 为 0.第二个文件 00000000000000001018.index 的消息量起始偏移量为 1019 = 1018 + 1. 同样,第三个文件 00000000000000002042.index 的起始偏移量为 2043=2042 + 1 ,其他后续文件依次类推,以起始偏移量命名并排序这些文件,只要根据 offset 二分查找文件列表,就可以快速定位到具体文件。当 offset=1066 时定位到 00000000000000001018.index|log 。 (2)通过 segment file 查找 message

  通过第一步定位到 segment file ,当 offset=1066 时,依次定位到 00000000000000001018.index 的元数据物理位置和 00000000000000001018.log 的物理偏移地址,此时我们只能拿到 1065 的物理偏移地址,然后再通过 00000000000000368769.log 顺序查找直到 offset=1066 为止。 每个 message 都有固定的格式很容易判断是否是下一条消息。   

kafka怎么查看分区 kafka查看分区文件在哪里_数据_04



  - END -