Kafka消息与索引详解

前言

以kafka_2.13-2.8.0为例,分析Kafka消息在磁盘上的存储结构、配置以及如何通过索引找到具体的消息数据。

分区目录

一个分区(Partition)有1到多个副本(Replica),是主从结构,主(Leader)负责处理读写请求,从(Follower)只负责同步数据并在主宕机的时候顶替主实现高可用。

在Kafka数据目录下存放着各分区目录(Partition),名称格式为 topic-partitionNo,如test-0代表名为test的Topic的0号分区。分区目录下存放消息的文件。

分段日志和索引

Kafka的消息是分段(Segment)存储在文件里的,当达到配置指定的条件就会创建新的分段文件。

每个分段都都对应消息日志(.log),偏移量索引(.index)和时间索引(.timeindex)三个文件,文件名为起始偏移量(Offset),代表这个文件第一条消息的偏移量值。

image-20210923181104770

以下是日志分段和索引创建的配置项,详情见 Apache Kafka Broker 配置。除了log.index.interval.bytes只影响单个索引的创建时机,其他配置都会触发日志分段。

配置项默认值单位描述
log.roll.msnull毫秒新日志段滚出的最大时间。如果未设置,则使用log.roll.hours中的值
log.roll.hours168小时新日志段滚出的最大时间,从属于log.roll.ms属性
log.segment.bytes1073741824(1G)B单个日志文件的最大大小
log.index.size.max.bytes10485760(1MB)B偏移索引的最大字节数
log.index.interval.bytes4096 (4 KB)B将一个项添加到偏移索引中的间隔

消息具体结构

消息日志与索引关系

Kafka数据最终都会保持在磁盘上,对于消息有三个关键的文件消息日志(.log),偏移量索引(.index)和时间索引(.timeindex)。

消息日志保存的是消息的原数据,接收到的生产者(Producer)的消息会以追加的方式顺序写到这个文件中,顺序写效率远高于随机写,减轻了磁盘寻址压力。这是Kafka使用磁盘做存储却能保证高性能的原因之一。

每个消息都会有一个自增的偏移量值,从0开始,每条消息都递增这个值,所以偏移量代表即将到来的下一条消息的偏移量值。

Kafka中索引有偏移量索引和时间索引两种。它没有为每一条消息建立索引,那样索引文件会太过于庞大,而是分段建立,所以一个索引只能指明消息所在位置的范围,最终要在这个范围遍历查找。

时间索引指向的是偏移量索引,偏移量索引指向了消息日志二进制位置。通过时间戳或者偏移量最终都可以定位到消息的具体位置。

可以通过配置参数 log.index.interval.bytes控制两个索引间隔的字节数,超过这个大小就建立新索引。这个值越小,索引越密集,查询快但是文件体积大。

消息日志(.log)

通过消息日志(.log)可以看到每条消息具体的内容。

# 只输出消息日志描述信息
kafka-dump-log.sh --files /var/kafka-logs/test-0/00000000000000023147.log

# 输出消息日志完整信息
kafka-dump-log.sh --files /var/kafka-logs/test-0/00000000000000023147.log --print-data-log

可以看到下图这个消息日志起始偏移量(Starting offset)是23147,代表这个日志第一条消息的偏移量,这个偏移量同时也是消息日志和两个索引文件的文件名。

每n条消息组成一批(batch),每一批消息对应有一个描述信息,记录了这批消息的大小,偏移量范围baseOffset和lastOffset,位置(position)以及大小(batchSize)等信息。

描述信息下面就是对应这一批具体的消息。如下图:

image-20210924142200778

偏移量索引(.index)

# 查看偏移量索引内容
kafka-dump-log.sh --files /var/kafka-logs/test-0/00000000000000023147.index

偏移量索引是稀疏结构,每隔一段记录一条消息的索引。Offset指消息的偏移量,position指这个偏移量的消息所在的一批(batch)消息在.log中的起始二进制位置。

image-20210924133848252

时间索引(.timeindex)

# 查看时间索引内容
kafka-dump-log.sh --files /var/kafka-logs/test-0/00000000000000023147.timeindex

时间索引也是稀疏结构,每隔一段记录一条消息的索引。时间戳(timestamp)指这条消息的创建时间,Offset指这个消息的偏移量。

上面这条指令同时会输出根据时间戳索引查找消息的结果,比如创建时间为1632390207745的消息偏移量为23388,这条消息所在那一批消息的起始偏移量(Indexed offset / baseOffset:)为23388,终止偏移量(found log offset / lastOffset:)为23390,这一批消息一起有23390 ~ 23388 = 3条消息。

image-20210924144857725

通过索引检索消息过程

通过时间戳检索消息

以查创建时间(CreateTime)为1632390207806的消息为例

去时间索引文件(.timeindex)中比较时间戳可以得到处于1632390207745~1632390208071区间,那对应的偏移量(offset)区间为23388 ~23475;

image-20210924135541306

去偏移量索引(.index)中比较偏移量可以得到这个这个时间范围对应的偏移量(offset)区间为2330723479,对应消息批次(batch)二进制地址(position)区间为827916648。

image-20210924151134134

再通过二进制地址(position)区间在消息日志(.index)中进行二分查找,找到匹配的三条数据offset=23400、23401、23402

image-20210924151609384

image-20210924152144448

image-20210924151816933

一批消息创建时间不一致

看到这发现每个批次的描述信息的创建时间好像和这一批消息的创建时间是一样的,但仔细查看虽然大多是这样,但也有不一样的。如下图:

image-20210924153115826

通过偏移量检索消息

以偏移量(offset)为23350的消息为例。

去偏移量索引(.index)中比较偏移量可以得到这个这个时间范围对应的偏移量(offset)区间为2322823307,对应消息批次(batch)二进制地址(position)区间为41718279。

image-20210924154107761

再通过二进制地址(position)区间在消息日志(.index)中进行顺序查找,最终找到对应数据。

image-20210924154658237

image-20210924154823517

image-20210924154737140

参考链接

Apache Kafka Broker 配置

Apache Kafka Documentation

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Kafka的offset是用来标识消息在分区中的位置的。每个分区都有一个对应的offset,用于记录消费者已经读取的消息位置。当消费者消费消息后,会向Kafka的broker中的一个专门维护每个消费者offset的topic发送一条消息,记录自己当前已读的消息的offset+1的值作为新的offset的消息。这样,下次消费者继续消费时,就可以从上次消费的位置继续读取消息。\[1\] Kafka的分区数据在磁盘上划分为多个segment,每个segment由索引文件和数据文件两个文件组成。每个segment文件根据设定的配置,最多存储相同大小的消息。每一个segment的文件都以自己文件里存储的第一消息的上一个offset作为文件名,这样可以更加灵活地分片存储以及快速查找。\[2\] Kafka将不同分区放到不同的broker上,其中一台作为leader,其他为isr(in-sync replicas)或者不在isr中。Kafka的leader负责写入消息,isr的其他成员异步地去同步这些消息。当isr中的所有成员都成功同步了这条消息时,这条消息对于消费端才可见。Kafka使用一个高水位(high watermark)来表示消费者所能读取到的最大的下一个offset。当leader接收到消息后,会先判断isr中成员的offset,如果不是最大+1,代表isr中有成员还没有接收到这条消息,则不会更改高水位。只有当isr中的每台机器的offset都比leader大1时,leader才会更新高水位,并将更新高水位的消息发送给isr中的follower。如果有follower宕机,会被剔除出isr,所以最坏情况下也会将所有follower都剔除,只对自己更新高水位。其他broker在重新加入集群后再同步消息。\[3\] #### 引用[.reference_title] - *1* *2* *3* [kafka的offset理解](https://blog.csdn.net/weixin_44627989/article/details/104891945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我有八千部下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值