Kafka作为大数据技术生态的重要组件,尤其是实时流数据处理场景下,作为分布式生产/消费系统,得到广泛的重用。而Kafka在数据生产和消费上,日志是主要的场景。今天的大数据开发学习分享,我们就来讲讲kafka日志结构的基础。

Java kafka 日志聚合 kafka的日志_Java kafka 日志聚合

Kafka消息是以主题为单位,主题之间相互独立。每个主题又由一个或多个分区构成,分区数可以在创建主题时指定,也可以在主题创建后再修改,但只能增加一个主题的分区数而不能减少其分区数。每个分区可以有一个或多个副本。

在存储结构上分区的每个副本对应一个Log对象,每个Log又划分为多个LogSegment,每个LogSegment包括一个日志文件和两个索引文件,其中两个索引文件分别为偏移量索引文件和时间戳索引文件。Log对象中维护了一个ConcurrentSkipListMap,底层是一个跳跃表,保存该主题所有分区对应的所有LogSegment。日志文件和索引文件与磁盘上的物理存储文件相对应。

Kafka将日志文件封装为一个FileMessageSet对象,将两个索引文件封装为OffsetIndex和TimeIndex对象。

1.数据文件

数据文件用来存储消息,每条消息由一个固定长度的消息头和一个可变长度的消息体数据组成。消息体包括一个可变长度的消息Key和消息实际数据Value,消息Key可以为空,消息结构如下图所示:

Java kafka 日志聚合 kafka的日志_Java kafka 日志聚合_02

消息结构各字段说明:

CRC32:CRC32校验和

magic:kafka服务程序协议版本号

attributes:低两位用来表示压缩方式,第三位表示时间戳类型,高4位预留

timestamp:消息时间戳,当magic大于0时消息头必须包含该字段

key-length:消息key的长度

key:消息key实际数据

payload-length:消息体实际数据长度

payload:消息体实际数据

在实际存储时一条消息总长度还包括12字节额外的开销,其中8字节长度记录消息的偏移量,消息的偏移量是相对该分区下第一个数据文件的基准偏移量而言,用来确定消息在分区下的逻辑位置,同一个分区下的消息偏移量按序递增,另外4字节表示消息总长度。因此在0.10.1版本Kafka一条消息的固定长度为34字节,所以在数据文件中相邻两条消息的position值之差减去34,即为消息Key和消息数据Value的总长度。

数据文件的大小由配置项log.segment.bytes指定,默认为1GB。同时Kafka提供了根据时间来切分日志段的机制,即使数据文件大小没有达到log.segment.bytes设置的阈值,但达到了log.roll.ms或是log.roll.hours设置的阈值,同样会创建新的日志段,在磁盘上创建一个数据文件和两个索引文件。接收消息追加操作的日志段也称为活跃段activeSegment。

2.偏移量索引文件

为了提高查找效率,Kafka为每个数据文件创建了一个基于偏移量的索引文件,数据文件同名,后缀为.index。

偏移量索引文件用来存储索引,索引是用来将偏移量映射成消息在数据文件中的物理位置,每个索引条目由offset和position组成,每个索引条目唯一确定数据文件中的一条消息。索引条目的offse和position与数据文件中消息的offse和position一一对应的,例如,数据文件中某条消息为offset:8和position:0,若为该条消息创建了索引,索引文件中索引值为offset:8和position:0。

并不是每条消息都对应有索引,kafka采用了稀疏存储的方式,每隔一定字节的数据建立一条索引,可以通过index.interval.bytes设置索引跨度。

每次写消息到数据文件时会检查是否要向索引文件写入索引条目,创建一个新索引条目的条件为:距离前一次写索引后累计消息字节数大于index.interval.bytes配置值。具体实现是LogSegment维持一个int类型的变量bytesSinceLastIndexEntry,初始值为0,每次写消息时先判断该值是否大于索引跨度。若小于索引跨度,则将该条消息的字节长度累加到变量bytesSinceLastIndexEntry中;否则会为该条消息创建一个索引条目写入索引文件,然后将bytesSinceLastIndexEntry重置为0。

3.时间戳索引文件

时间戳索引文件与数据文件同名,以.timeindex后缀,该索引文件包括一个8字节长度的时间戳字段和一个4字节的偏移量字段,其中时间戳记录的是该日志段目前为止最大时间戳,偏移量则记录的是插入新的索引条目时,当前消息的偏移量。

该索引文件索引条目之间的跨度由index.interval.bytes设置的阈值决定,但同时必须保证新创建的索引条目的时间戳大于上一个索引的时间戳。

时间戳索引也采用了稀疏存储的方式,索引条目对应的时间戳的值及偏移量与数据文件中相应消息的这两个字段的值相同。同时在记录偏移量索引条目时会判断是否需要同时写时间戳索引。

关于大数据学习,Kafka日志结构,以上就为大家做了基本的讲解了。Kafka在实时消息流的生产和消费上,其稳定性和可靠性,依赖于存储,对于日志结构这部分,建议大家一定要理解透彻。