ps:该图引用下面kafka日志版本的演变的博客
1.查找offset=350的消息,先二分查找确定消息在哪个segment中
2.到对应segment的.index文件中找到小于350的最大偏移量,即 345,其对应的物理位置是328
3.根据物理位置328,直接定位到.log文件的328文件位置
4.顺序读取每条消息的偏移量,但不读取消息内容
5.找到offset=350的消息,得到物理位置为448
6.开始真正读取offset=350的消息内容并返回
在默认的删除规则之外提供的另一种数据清除策略,对于有相同key的的不同value值,只保留最后一个版本 kafka中
用于保存消费者消费位移的主题”__consumer_offsets”使用的就是log compaction策略
每个日志目录下,有名为”cleaner-offset-checkpoint”的文件,根据该文件可以将日志文件分成2部分
clean部分:偏移量是断续的,经过压缩的部分
dirty部分:偏移量是连续的,未清理过的部分
activeSegment部分:活跃的热点数据,不参与log campaction,默认情况下firstUncleanableOffset等于activeSegment的baseOffset
log campaction使用时应注意每个消息的key值不为null,这种方式当客户端进行消费时总能赶上dirty部分的情况,它就能读取到日志的所有消息,反之,就不可能读到全部的消息
如何确选择合适的log文件进行清理:
选择污浊率最高的,可通过配置log.cleaner.min.cleanable.ratio参数(默认0.5)
dirtyRatio = dirtyBytes / (cleanBytes + dirtyBytes)
如何对log文件中消息的key进行筛选:
1.创建一个名为”SkimpyOffsetMap”的哈希表来构建key与offset的映射表
2.遍历第一遍log文件,把每个key的hashCode和最后出现的offset都保存在SkimpyOffsetMap中
3.遍历第二遍log文件,检查每个消息是否符合保留条件,如果符合就保留下来,否则就会被清理掉
保留条件:假设一条消息的offset为O1,这条消息的key在SkimpyOffsetMap中所对应的offset为O2,如果O1>=O2即为满足保留条件
hash冲突处理:采用线性探测法来处理哈希冲突
缺点:遇到两个不同的key但哈希值相同的情况,那么其中一个key所对应的消息就会丢失
日志压缩步骤举例:
1.第一次日志压缩,清理点为0,日志头部的范围从0到活动分段的基准偏移量13
2.第一次压缩后,清理点更新为13,第二次日志压缩时,日志头部范围从13到活动日志分段的基准偏移量20,日志尾部范围从0到清理点的位置13
3.第二次压缩后,清理点更新为20,第三次日志压缩时,日志头部范围从20到活动日志分段的基准偏移量28,日志尾部范围从2到清理点的位置20
日志压缩合并:
1.第一次日志压缩,清理点等于0,没有尾部日志,日志头部从6:00带7:40,所有日志分段文件都是1GB,不考虑删除的消息
2.第一次日志压缩后,清理点改为日志头部末尾即7:40,每个新日志分段的大小都小于1GB
3.第二次日志压缩时,清理点为7:40,日志头部从8:00到8:10,日志尾部从6:00到7:40,压缩操作会将多个小文件分成1组,每一组不超过1GB
https://www.cnblogs.com/qwangxiao/p/9043491.html
1.为每个producer设置唯一的PID
2.引入了序列号字段sequence number,标识某个producer发送的每批消息,sequence number是从0开始严格单调递增的
3.broker端会为每个PID(即每个producer)保存该producer发送过来的消息batch的某些元信息(如PID信息、消息batch的起始seq number及结束seq number等)
4.每当该PID发送新的消息batch时,Kafka broker就会对比这些信息,如果发生冲突(比如起始seq number和结束seq number与当前缓存的相同),那么broker就会拒绝这次写入请求;倘若没有冲突,那么broker端就会更新这部分缓存然后再开始写入消息
总结:为每个producer设置唯一的PID并引入seq number以及broker端seq number缓存更新机制来去重