前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Kafak-分布式日志存储系统的设计与高吞吐实践

Kafak-分布式日志存储系统的设计与高吞吐实践

作者头像
运维小路
发布2025-06-07 17:20:07
发布2025-06-07 17:20:07
4900
代码可运行
举报
文章被收录于专栏:运维小路运维小路
运行总次数:0
代码可运行

作者介绍:简历上没有一个精通的运维工程师,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

我们上一章介绍了中间件:Zookeeper,本章将介绍另外一个中间件:Kafka。目前这2个中间件都是基于JAVA语言的。

我们前面讲解了Kafka的几个关键概念,生产者者发送的消息最终都会写到Broker节点的磁盘里面,那么它在本地数据是怎么样的呢?

1. Kafka 日志的核心设计

Kafka 的日志(Log)是其存储模型的核心,采用 顺序追加写入(Append-Only)分段存储(Segment) 的设计,确保高吞吐量和持久化能力。

核心特性
代码语言:javascript
代码运行次数:0
运行
复制
所有消息按顺序追加到日志末尾,避免随机磁盘寻址,极大提升写入性能。

2. 日志存储结构

物理目录结构
代码语言:javascript
代码运行次数:0
运行
复制
# Topic: my-topic,分区 0 的存储目录
my-topic-0/
├── 00000000000000000000.log    # Segment 日志文件(存储实际消息)
├── 00000000000000000000.index  # 位移索引文件(快速定位消息位置)
├── 00000000000000000000.timeindex  # 时间戳索引文件(按时间查找消息)
├── 00000000000000000005.log
├── 00000000000000000005.index
└── ...
下面就是我使用生产者写了很多内容的真实Topic的其中一个分区。可以看到已经有2组文件,第一组全是0的文件是初始的内容,所以它的偏移量都是0,第二组文件从名字来看它的偏移量已经达到1000W+。
代码语言:javascript
代码运行次数:0
运行
复制
[root@localhost my-topic123-0]# ll
total 1315664
-rw-r--r-- 1 root root    1634712 May  9 01:11 00000000000000000000.index
-rw-r--r-- 1 root root 1073741798 May  9 01:11 00000000000000000000.log
-rw-r--r-- 1 root root    2452080 May  9 01:11 00000000000000000000.timeindex
-rw-r--r-- 1 root root   10485760 May  9 01:41 00000000000011386211.index
-rw-r--r-- 1 root root  265066873 May  9 01:41 00000000000011386211.log
-rw-r--r-- 1 root root         10 May  9 01:11 00000000000011386211.snapshot
-rw-r--r-- 1 root root   10485756 May  9 01:41 00000000000011386211.timeindex
-rw-r--r-- 1 root root          8 May  8 22:32 leader-epoch-checkpoint
根据副本和分区,每个Topic日志目录会均匀分布在各个broker节点上。比如上图的my-topic就是Topic的名字,后面的0就是分区号。如果是3节点3分区3副本,哪么每个节点都会存在my-topic-0,my-topic-1,my-topic-2,3个目录(具体以现场环境为准)。这3个分区里面可能就有leader分区和flower分区。
日志文件内容
  • 消息格式:每条消息包含元数据(Offset、Timestamp、Key、Value 等)。
  • 存储示例
代码语言:javascript
代码运行次数:0
运行
复制
#真实消息存储 
[root@localhost my-topic123-0]# /root/kafka_2.13-2.8.2/bin/kafka-dump-log.sh --files  ./00000000000011386211.log --print-data-log |more
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
Dumping ./00000000000011386211.log
Starting offset: 11386211
baseOffset: 11386211 lastOffset: 11386225 count: 15 baseSequence: -1 lastSequence: -1 producerId: -1 producerEpoch: -1 partitionLeaderEpoch: 0 isTransactional: false isControl: false position: 0 CreateTime: 1746724313903 size: 1441 magic: 2 compresscodec: NONE crc: 3132510745 isvalid: true
| offset: 11386211 isValid: true crc: null keySize: -1 valueSize: 83 CreateTime: 1746724313899 baseOffset: 11386211 lastOffset: 11386225 baseSequence: -1 lastSequence: -1 producerEpoch: -1 partitionLeaderEpoch: 0 batchSize: 1441 magic: 2 compressType: NONE position: 0 sequence: -1 headerKeys: [] payload: {"timestamp": "2025-05-09 01:11:53", "count": 34152860,
 "data": "Message-34152860"}
| offset: 11386212 isValid: true crc: null keySize: -1 valueSize: 83 CreateTime: 1746724313899 baseOffset: 11386211 lastOffset: 11386225 baseSequence: -1 lastSequence: -1 producerEpoch: -1 partitionLeaderEpoch: 0 batchSize: 1441 magic: 2 compressType: NONE position: 0 sequence: -1 headerKeys: [] payload: {"timestamp": "2025-05-09 01:11:53", "count": 34152861,
 "data": "Message-34152861"}
| offset: 11386213 isValid: true crc: null keySize: -1 valueSize: 83 CreateTime: 1746724313899 baseOffset: 11386211 lastOffset: 11386225 baseSequence: -1 lastSequence: -1 producerEpoch: -1 partitionLeaderEpoch: 0 batchSize: 1441 magic: 2 compressType: NONE position: 0 sequence: -1 headerKeys: [] payload: {"timestamp": "2025-05-09 01:11:53", "count": 34152862,
 "data": "Message-34152862"}
| offset: 11386214 isValid: true crc: null 
代码语言:javascript
代码运行次数:0
运行
复制
#偏移量offset记录 
[root@localhost my-topic123-0]# /root/kafka_2.13-2.8.2/bin/kafka-dump-log.sh --files  ./00000000000011386211.index --print-data-log |more
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
Dumping ./00000000000011386211.index
offset: 11386508 position: 26767
offset: 11386567 position: 32194
offset: 11386626 position: 37437
offset: 11386676 position: 42159
代码语言:javascript
代码运行次数:0
运行
复制
#时间戳和偏移量的记录 
[root@localhost my-topic123-0]# /root/kafka_2.13-2.8.2/bin/kafka-dump-log.sh --files  ./00000000000011386211.timeindex --print-data-log |more
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
Dumping ./00000000000011386211.timeindex
timestamp: 1746724314114 offset: 11386508
timestamp: 1746724314170 offset: 11386567
timestamp: 1746724314210 offset: 11386626
timestamp: 1746724314236 offset: 11386676
timestamp: 1746724314263 offset: 11386721
timestamp: 1746724314301 offset: 11386767

当然我们一般不会使用脚本去读取这些信息,我这里通过Kafka自带的脚本只是为了方便理解这里的信息。

3. 存储机制

写入流程
  1. 生产者发送消息:消息被发送到 Topic 的某个分区的Leader副本。
  2. 追加到 Leader 副本的日志
    • 消息按顺序写入当前活跃 Segment 文件(如 000000000000005.log)。
    • 同步更新对应的索引文件(.index.timeindex)。
  3. 副本同步
    • Follower 副本从 Leader 副本拉取消息,写入本地日志(保证数据冗余)。
读取流程
  1. 消费者指定 Offset:消费者通过 Offset 请求特定消息。
  2. 二分查找索引文件
    • 使用 .index 文件快速定位消息在日志文件中的物理位置。
  3. 直接读取磁盘数据:通过零拷贝技术将数据发送给消费者。

4. 存储策略

数据保留策略
代码语言:javascript
代码运行次数:0
运行
复制
保留最近 N 天的数据(默认 7 天),由 log.retention.hours 控制。
日志清理
  • 删除策略:过期 Segment 文件会被自动删除(由 log.cleanup.policy=delete 控制)。
  • 压缩策略:日志压缩后,仅保留每个 Key 的最新消息(由 log.cleanup.policy=compact 控制)。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维小路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Kafka 日志的核心设计
    • 核心特性
  • 2. 日志存储结构
    • 物理目录结构
    • 下面就是我使用生产者写了很多内容的真实Topic的其中一个分区。可以看到已经有2组文件,第一组全是0的文件是初始的内容,所以它的偏移量都是0,第二组文件从名字来看它的偏移量已经达到1000W+。
    • 根据副本和分区,每个Topic日志目录会均匀分布在各个broker节点上。比如上图的my-topic就是Topic的名字,后面的0就是分区号。如果是3节点3分区3副本,哪么每个节点都会存在my-topic-0,my-topic-1,my-topic-2,3个目录(具体以现场环境为准)。这3个分区里面可能就有leader分区和flower分区。
    • 日志文件内容
  • 3. 存储机制
    • 写入流程
    • 读取流程
  • 4. 存储策略
    • 数据保留策略
    • 日志清理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档