Kafka 的存储内部是如何工作的

82 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

Kafka的存储单元是partition

分区是附加到的有序的、不可变的消息序列。分区不能跨多个代理甚至多个磁盘拆分。

保留策略管理 Kafka 如何保留消息

您指定应保留多少数据或多长时间的数据,之后 Kafka 将按顺序清除消息——无论消息是否已被使用。

image.png

分区被分割成段

所以 Kafka 需要定期查找磁盘上需要清除的消息。对于分区消息的单个非常长的文件,此操作很慢且容易出错。为了解决这个问题(以及我们将看到的其他问题),分区被分成多个段。

当 Kafka 写入一个分区时,它写入一个段——活动段。如果达到段的大小限制,则会打开一个新段并成为新的活动段。

段以其基本偏移量命名。段的基本偏移量是大于先前段中的偏移量且小于或等于该段中的偏移量的偏移量。

image.png

在磁盘上,一个分区就是一个目录,每个段就是一个索引文件和一个日志文件。

$ tree kafka | head -n 6  
kafka  
├── events-1  
│ ├── 00000000003064504069.index  
│ ├── 00000000003064504069.log  
│ ├── 00000000003065011416.index  
│ ├── 00000000003065011416.log

段日志是存储消息的地方

每条消息都是它的值、偏移量、时间戳、密钥、消息大小、压缩编解码器、校验和以及消息格式的版本。

磁盘上的数据格式与代理通过网络从生产者接收并发送给其消费者的数据格式完全相同。这使得 Kafka 能够以零拷贝的方式高效传输数据。

$ bin/kafka-run-class.sh kafka.tools.DumpLogSegments --deep-iteration --print-data-log --files /data/kafka/events-1/00000000003065011416.log | head -n 4
Dumping /data/kafka/appusers-1/00000000003065011416.log
Starting offset: 3065011416
offset: 3065011416 position: 0 isvalid: true payloadsize: 2820 magic: 1 compresscodec: NoCompressionCodec crc: 811055132 payload: {"name": "Travis", msg: "Hey, what's up?"}
offset: 3065011417 position: 1779 isvalid: true payloadsize: 2244 magic: 1 compresscodec: NoCompressionCodec crc: 151590202 payload: {"name": "Wale", msg: "Starving."}

段索引将消息偏移量映射到它们在日志中的位置

段索引将偏移量映射到它们的消息在段日志中的位置。

image.png

索引文件是内存映射的,偏移量查找使用二分查找找到最近的小于或等于目标偏移量的偏移量。

索引文件由 8 个字节的条目组成,4 个字节用于存储相对于基本偏移量的偏移量,4 个字节用于存储位置。偏移量是相对于基本偏移量的,因此只需要 4 个字节来存储偏移量。例如:假设基本偏移量是 10000000000000000000,而不是必须存储后续偏移量 1000000000000000001 和 100000000000000000002 它们只是 1 和 2。

Kafka 将压缩消息打包在一起

发送压缩消息的生产者会将批次压缩在一起,并将其作为包装消息的有效负载发送。和以前一样,磁盘上的数据与代理通过网络从生产者接收并发送给消费者的数据完全相同。

image.png

我们来复习

现在你知道 Kafka 存储内部是如何工作的了:

  • Partitions是Kafka的存储单元
  • 分区被分割成段
  • 段是两个文件:它的日志和索引
  • 索引将每个偏移量映射到它们在日志中的消息位置,它们用于查找消息
  • 索引存储相对于其段的基本偏移量的偏移量
  • 压缩的消息批次被包装在一起作为包装消息的有效负载
  • 存储在磁盘上的数据与代理通过网络从生产者接收并发送给其消费者的数据相同