物理存储
日志存储概述
Kafka 消息是以主题为单位进行归类,各个主题之间是彼此独立的,互不影响。
每个主题又可以分为一个或多个分区。
每个分区各自存在一个记录消息数据的日志文件。
图中,创建了一个 tp_demo_01 主题,其存在6个 Parition,对应的每个Parition下存在一个
[Topic-Parition] 命名的消息日志文件。在理想情况下,数据流量分摊到各个 Parition 中,实现了负
载均衡的效果。在分区日志文件中,你会发现很多类型的文件,比
如: .index、.timestamp、.log、.snapshot 等。
其中,文件名一致的文件集合就称为 LogSement。
LogSegment
- 分区日志文件中包含很多的 LogSegment
- Kafka 日志追加是顺序写入的
- LogSegment 可以减小日志文件的大小
- 进行日志删除的时候和数据查找的时候可以快速定位。
- ActiveLogSegment 是活跃的日志分段,拥有文件拥有写入权限,其余的 LogSegment 只有只读的权限。
类别作用
日志文件存在多种后缀文件,重点需要关注 .index、.timestamp、.log 三种类型。
每个 LogSegment 都有一个基准偏移量,表示当前 LogSegment 中第一条消息的 offset。
偏移量是一个 64 位的长整形数,固定是20位数字,长度未达到,用 0 进行填补,索引文件和日志文件都由该作为文件名命名规则(00000000000000000000.index、00000000000000000000.timestamp、00000000000000000000.log)。
如果日志文件名为 00000000000000000121.log ,则当前日志文件的一条数据偏移量就是121(偏移量从 0 开始)。
日志与索引文件
配置项默认值说明
偏移量索引文件用于记录消息偏移量与物理地址之间的映射关系。
时间戳索引文件则根据时间戳查找对应的偏移量。
Kafka 中的索引文件是以稀疏索引的方式构造消息的索引,并不保证每一个消息在索引文件中都有对应的索引项。
每当写入一定量的消息时,偏移量索引文件和时间戳索引文件分别增加一个偏移量索引项和时间戳索引项。
通过修改 log.index.interval.bytes 的值,改变索引项的密度。
切分文件
当满足如下几个条件中的其中之一,就会触发文件的切分:
- 当前日志分段文件的大小超过了 broker 端参数 log.segment.bytes 配置的值。log.segment.bytes 参数的默认值为 1073741824,即 1GB。
- 当前日志分段中消息的最大时间戳与当前系统的时间戳的差值大于 log.roll.ms 或log.roll.hours 参数配置的值。如果同时配置了 log.roll.ms 和 log.roll.hours 参数,那么 log.roll.ms 的优先级高。默认情况下,只配置了 log.roll.hours 参数,其值为168,即 7 天。
- 偏移量索引文件或时间戳索引文件的大小达到 broker 端参数 log.index.size.max.bytes配置的值。 log.index.size.max.bytes 的默认值为 10485760,即 10MB。
- 追加的消息的偏移量与当前日志分段的偏移量之间的差值大于 Integer.MAX_VALUE ,即要追加的消息的偏移量不能转变为相对偏移量。
为什么是 Integer.MAX_VALUE ?
1024 * 1024 * 1024=1073741824
在偏移量索引文件中,每个索引项共占用 8 个字节,并分为两部分。
相对偏移量和物理地址。
相对偏移量:表示消息相对与基准偏移量的偏移量,占 4 个字节
物理地址:消息在日志分段文件中对应的物理位置,也占 4 个字节
4 个字节刚好对应 Integer.MAX_VALUE ,如果大于 Integer.MAX_VALUE ,则不能用 4 个字节进行表示了
索引文件切分过程
索引文件会根据 log.index.size.max.bytes 值进行预先分配空间,即文件创建的时候就是最大值
当真正的进行索引文件切分的时候,才会将其裁剪到实际数据大小的文件。
这一点是跟日志文件有所区别的地方。其意义降低了代码逻辑的复杂性。
日志存储
索引
偏移量索引文件用于记录消息偏移量与物理地址之间的映射关系。时间戳索引文件则根据时间戳查找对应的偏移量。
文件:
查看一个topic分区目录下的内容,发现有log、index和timeindex三个文件:
- log文件名是以文件中第一条message的offset来命名的,实际offset长度是64位,但是这里只使用了20位,应付生产是足够的。
- 一组index+log+timeindex文件的名字是一样的,并且log文件默认写满1G后,会进行logrolling形成一个新的组合来记录消息,这个是通过broker端log.segment.bytes =1073741824指定的。
- index和timeindex在刚使用时会分配10M的大小,当进行 log rolling 后,它会修剪为实际的大小。