Kafka系列之--kafka日志存储

⽂件⽬录

1、存储结构:
在这里插入图片描述
当Log(日志)文件达到一定阈值的时候,会分成多个LogSegment(日志分段文件)

2、目录结构:
在这里插入图片描述

⽂件滚动

在这里插入图片描述
✓ 默认情况下,每个⽚段包含1G或7天的数据,以较⼩的值为准;如果达到⽚段上限,就关闭当前⽂件,并打开⼀个新⽂件

⽇志索引

在Kafka文件存储中,同一个topic下有多个不同的partition,每个partiton为一个目录,partition的名称规则为topic名称+有序序号,第一个序号从0开始计,最大的序号为partition数量减1,partition是实际物理上的概念,而topic是逻辑上的概念,更多表象是一个消息的类别,当然,partition还可以细分为segment,一个partition物理上由多个segment组成;

引发第一个疑问,为什么不能以partition 作为存储单位?
如果就以partition 为最小存储单位,可以想象,当Kafka producer不断发送消息,必然会引起partition文件的无限扩张,将对消息文件的维护以及已消费的消息的清理带来严重的影响,新数据是在文件尾部追加的,不论文件数据文件有多大,这个操作永远都是 O(1)的查找,再者,查找某个offset的Message是顺序查找的。因此,如果数据文件很大的话,查找的效率就低. 因此,需以segment 为单位将partition进一步细分。每个partition相当于一个巨型文件被平均分配到多个大小相等的segment数据文件中(每个segment文件中消息数量不一定相等)这种特性也方便old segment的删除,即方便已被消费的消息的清理,提高磁盘的利用率。每个partition只需要支持顺序读写就行.segment的文件生命周期由服务端配置参数log.segment.bytes,log.roll.{ms,hours} 等相关参数决定。 segment文件由两部分组成,分别为 .index文件和.log文件,分别表示为segment索引文件和数据文件。这两个文件的命令规则为:partition全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值,数值大小为64位,20位数字字符长度,没有数字用0填充,如下:
在这里插入图片描述
以上面的segment文件为例,展示出segment:00000000000000000000的.index文件和.log文件的对应的关系,如下图:
在这里插入图片描述
如上图,00000000000000000000.index索引文件存储的时一对key-value,其中key(offset)是消息在数据文件00000000000000000000.log中的编号(offset)对应的比如:8499、8544、8589、8634分别表示在00000000000000000000.log文件中第多少条消息。索引文件中使用的是稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免索引文件占用过多的空间,从而可以将索引文件保留在内存中,缺点不能一次定位到数据文件的位置,需要一次顺序扫描,但是扫描范围就很小了.
如何从partition中通过offset查找message
【8499,778378】为例,在00000000000000000000.log数据文件中表示第8499个消息,即在全局partition中position中为0+778378=778378,该消息在00000000000000000000.log数据文件中的物理偏移地址为8499

数据在.log文件的存储

1、创建一个topic: topic_log_0619 3一个分区 3个备份,便于测试观察

[root@master kafka_2.11-2.4.1]# bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files ./kafka-log/topic_log_0619-0/00000000000000000000.index --print-data-log
Dumping ./kafka-log/topic_log_0619-0/00000000000000000000.index
offset: 47 position: 4172
offset: 93 position: 8312
offset: 139 position: 12452
offset: 185 position: 16592
offset: 231 position: 20732
offset: 277 position: 24872
offset: 323 position: 29012
offset: 368 position: 33150
offset: 413 position: 37290
offset: 458 position: 41430
offset: 503 position: 45570

[root@slave1 kafka_2.11-2.4.1]# bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files ./kafka-log/topic_log-0/00000000000000000000.log --print-data-log
Dumping ./kafka-log/topic_log-0/00000000000000000000.log
Starting offset: 0
baseOffset: 0 lastOffset: 0 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 0 CreateTime: 1592559760366 size: 68 magic: 2 compresscodec: NONE crc: 4174411830 isvalid: true
| offset: 0 CreateTime: 1592559760366 keysize: -1 valuesize: 0 sequence: -1 headerKeys: [] payload: 
baseOffset: 1 lastOffset: 1 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 68 CreateTime: 1592559767394 size: 77 magic: 2 compresscodec: NONE crc: 2580841163 isvalid: true
| offset: 1 CreateTime: 1592559767394 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-1
baseOffset: 2 lastOffset: 2 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 145 CreateTime: 1592559772145 size: 77 magic: 2 compresscodec: NONE crc: 2349816861 isvalid: true
| offset: 2 CreateTime: 1592559772145 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-2
baseOffset: 3 lastOffset: 3 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 222 CreateTime: 1592559780057 size: 77 magic: 2 compresscodec: NONE crc: 2323647012 isvalid: true
| offset: 3 CreateTime: 1592559780057 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-3
baseOffset: 4 lastOffset: 4 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 299 CreateTime: 1592559782460 size: 77 magic: 2 compresscodec: NONE crc: 563922759 isvalid: true
| offset: 4 CreateTime: 1592559782460 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-4
baseOffset: 5 lastOffset: 5 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 376 CreateTime: 1592559785624 size: 77 magic: 2 compresscodec: NONE crc: 4123286198 isvalid: true
| offset: 5 CreateTime: 1592559785624 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-5
baseOffset: 6 lastOffset: 6 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 453 CreateTime: 1592559788434 size: 77 magic: 2 compresscodec: NONE crc: 4009027688 isvalid: true
| offset: 6 CreateTime: 1592559788434 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-6
baseOffset: 7 lastOffset: 7 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 530 CreateTime: 1592559791017 size: 77 magic: 2 compresscodec: NONE crc: 3140925100 isvalid: true
| offset: 7 CreateTime: 1592559791017 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-7
baseOffset: 8 lastOffset: 8 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 607 CreateTime: 1592559794379 size: 77 magic: 2 compresscodec: NONE crc: 2995811806 isvalid: true
| offset: 8 CreateTime: 1592559794379 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-8
baseOffset: 9 lastOffset: 9 count: 1 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 684 CreateTime: 1592559796803 size: 77 magic: 2 compresscodec: NONE crc: 3880436270 isvalid: true
| offset: 9 CreateTime: 1592559796803 keysize: -1 valuesize: 9 sequence: -1 headerKeys: [] payload: Message-9

补充第二个疑问,如何保证消息消费的有序性呢?
举个例子,比如说生产者生产了25个订单,订单假设分为创建-提交-付款-发货4个步骤,那么消费者在消费的时候按照0到100这个从小到大的顺序消费,那么kafka如何保证这种有序性呢?

难度就在于,生产者生产出0到100这100条数据之后,通过一定的分组策略存储到broker的partition中的时候,
比如0到10这10条消息被存到了这个partition1中,10到20这10条消息被存到了那个partition2中,这样的话,消息在分组存到partition中的时候就已经被分组策略搞得无序了。

那么能否做到消费者在消费消息的时候全局有序呢?遇到这个问题,我们可以回答,在大多数情况下是做不到全局有序的。但在某些情况下是可以做到的。比如我的partition只有一个,这种情况下是可以全局有序的。

那么可能有人又有疑问了,只有一个partition的话,哪里来的分布式呢?哪里来的负载均衡呢?所以说,全局有序是一个伪命题!让订单全局有序根本没有办法在kafka内部做到。但是我们只能保证当前这个partition内部消息消费的有序性。

结论:一个partition中的数据是有序的吗?回答:间隔有序,不连续。

针对一个topic里面的数据,只能做到partition内部有序,不能做到全局有序。特别是加入消费者的场景后,如何保证消费者的消费的消息的全局有序性,

这是一个伪命题,只有在一种情况下才能保证消费的消息的全局有序性,那就是只有一个partition!

当然不使用一个partition我们也有办法解决,从代码层面解决,我们可以借助于Set或者Redis,将多次收到的相同订单号的消息储存起来,等满足4条后再一并处理。

⽇志清理

磁盘存储

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值