问题导读
1.kafka的文件系统是存储方式?
2.kafka partiton文件存储结构有什么优势?
3.一个大文件为什么分成多个小文件段?
1.文件系统说明文件系统一般分为系统和用户2种类型,系统级文件系统:ext3,ext4,dfs,ntfs等等,,笔者并不会向大家介绍那种纷繁复杂的分布式或系统级文件系统,而是从kafka架构高性能角度考虑,深入剖析kafka文件系统存储结构设计。
2.kafka文件系统架构
2.1 文件系统数据流
下面用图形表示介绍客户端处理几个过程如下:
图1 - 当建立连接请求时,首先客户端向kafka broker发送连接请求,broker中由Acceptor thread线程接收并建立连接后,把client的socket以轮询方式转交给相应的processor thread。
- 当client向broker发送数据请求,由processor thread处理并接收client数据放到request缓冲区中,以待IO thread进行逻辑处理和计算并把返回result放到response缓冲区中.
接着唤醒processor thread,processor thread抱住response队列循环发送所有response数据给client.
2.2 kafka文件系统存储结构
图2 - paritions分布规则,kafka集群由多个kafka broker组成,一个topic的partitions会分布在一个或多个broker上,topic的partitions在kafka集群上分配规则为,安装paritions索引编号依次有序分布在broker上,
当partitions数量 > brokers数量,会依次轮回再次迭代分配。
- partitions命名规则,paritions名称为:topic-name-index, index分区索引编号,从0开始依次递增。
- producer,每个producer可以发送msg到topic任意一个或多个partitons。
- consumer,同一个Consumer Group中的Consumers,Kafka将相应Topic中的每个消息只发送给其中一个Consumer.
2.3 kafka的文件系统结构-目录
目前假如kafka集群中只有一个broker,数据文件目录为message-folder,例如笔者创建一个topic名称为:report_push, partitions=4 存储路径和目录规则为: xxx/message-folder |--report_push-0 |--report_push-1 |--report_push-2 |--report_push-3 形象表示图如下:
图3
2.4 kafka的文件系统结构-partiton文件存储方式
图4
每个partition(topic-name-index)目录中存储海量msg消息,那它是怎么存储的呢?文件存储结构是怎样? 这么多(海量)消息是存储在一个大文件中,类似DB那样存储,还是其他方式存储结构呢?笔者后续会像剥洋葱一样,给大家一层一层依次分解并分析。
- 数据库和kafka文件系统比较,相信大家都用过数据库,数据库底层文件系统相当复杂,因为数据库特点,需要按照关键字,id快速查询,修改,删除,日志,回滚等等。
所以数据库文件系统是分页存储的树形结构,需要支持大量随机事物操作。相比数据库支持查询,事物等等复杂文件,则kafka消息队列类型文件系统简单多了,kafka文件系统存储特点是,
只需要支持producer和consumer顺序生产和消息就够了,消息(msg)生命周期由consumer决定。
- partiton文件存储结构分析,每个partition就像如上图4,一个巨大文件消息数据被平均分配到多个文件大小相等的文件中。即相当于一个大文件被切成很多相等大小的文件段segment file
(消息数量不一定相等)。因为每个topic中消息生命周期由最后一个consumer决定,当某个或些消息被最后一个consumer(consumer group)消息后,就可以删除该消息。显然易见,
这样做的目的是broker能快速回收磁盘空间,而且小文件也能mmap全部到内存。主要目的就是提高磁盘利用率和消息处理性能。
2.5 kafka的文件系统结构-partiton文件存储segment file组成
读者从2.4节了解到kafka文件系统partition存储方式,下面向大家介绍一下partion文件存储中segement file组成结构。一个商业化消息队列的性能好坏, 其文件系统存储结构设计是衡量一个消息队列服务程序最关键指标之一,他也是消息队列中最核心且最能体现消息队列技术水平的部分。在本节中我们将走进segment file内部一探究竟。 segment file组成:由2大部分组成,分别为segment data file和segment index file,此2个文件一一对应,成对出现. segment index file索引文件组成结构如下: 00000000000000000000.index 文件名称,文件串大小最大支持2^64bit
-
- 每次记录相应log文件记录的相对条数和物理偏移位置位置,共8bytes
- 4byte 当前segment file offset - last seg file offset记录条数 offset
- 4byte对应segment file物理偏移地址 position
- ………
复制代码
segment data file索引文件组成结构如下:
00000000000000000000.log 文件名称,文件串大小最大支持2^64bit,与index对应 图5 参数说明: 4 byte CRC32:使用crc32算法计算除CRC32这4byte外的buffer。 1 byte “magic":表示数据文件协议版本号 1 byte “attributes":表示标识独立版本,标识压缩类型,编码类型。 key data:可选,可以存储判断或表示这个消息块的元数据信息。 payload data:消息体,该消息体可能会存储多条消息记录,内部是按照序号有序存储的。
2.6 kafka文件系统-consumer读取流程图6
segment index file: 稀疏索引方式,减少索引文件大小,这样可以直接内存操作,稀疏索引只为数据文件的每个存储块设一个键-指针对,它比稠密索引节省了更多的存储空间,但查找给定值的记录需更多的时间,通过二分查找快速找到segment data file物理位置,如果在index file没有找到data file具体位置,则data file相对位置继续顺序读取查找,直到找到为止。
2.7 kafka的文件系统结构-总体目录结构
图7 同一个topic下有不同分区,每个分区下面会划分为多个(段)文件,只有一个当前文件在写,其他文件只读。当写满一个文件(写满的意思是达到设定值)则切换文件,新建一个当前文件用来写,老的当前文件切换为只读。文件的命名以起始偏移量来命名。看一个例子,假设report_push这个topic下的0-0分区可能有以下这些文件: • 00000000000000000000.index • 00000000000000000000.log • 00000000000000368769.index • 00000000000000368769.log • 00000000000000737337.index • 00000000000000737337.log • 00000000000001105814.index • 00000000000001105814.log ……………….. 其中 00000000000000000000.index表示最开始的文件,起始偏移量为0.第二个文件00000000000000368769.index的消息量起始偏移量为368769.同样,第三个文件00000000000000737337.index的起始偏移量为737337. 以起始偏移量命名并排序这些文件,那么当消费者要拉取某个消息起始偏移量位置的数据变的相当简单,只要根据传上来的offset**二分查找**文件列表,定位到具体文件, 然后将绝对offset减去文件的起始节点转化为相对offset,即可开始传输数据。例如,同样以上面的例子为例,假设消费者想抓取从第368969消息位置开始的数据,则根据368969二分查找, 定位到00000000000000368769.log这个文件(368969在368769和737337之间),根据索引文件二分搜索可以确定读取数据最大大小。
2.8 kafka文件系统–实际效果
图8 基本不会有磁盘读的大量操作,都在内存进行,只有定期磁盘批量写操作。
3.总结 高效文件系统特点 - 一个大文件分成多个小文件段。
- 多个小文件段,容易定时清除或删除已经消费完文件,减少磁盘占用。
- index全部映射到memory直接操作,避免segment file被交换到磁盘增加IO操作次数。
- 根据索引信息,可以确定发送response到consumer的最大大小。
- 索引文件元数据存储用的是相对前一个segment file的offset存储,节省空间大小。
来自:http://blog.csdn.net/lizhitao/article/details/40543631
|