乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 消息队列与 Kafka 概述

    • 章节导读
    • 消息队列基础
    • Kafka 概述
    • Kafka 为什么快
  • 第2章 快速上手:单机环境搭建

    • 章节导读
    • 环境准备与安装
    • 快速启动
    • Topic 管理
  • 第3章 核心概念:主题、分区与日志

    • 章节导读
    • Topic
    • Partition
    • Offset
    • Segment 与存储结构
  • 第4章 生产者详解

    • 章节导读
    • Producer 概述
    • Producer 发送机制
    • Producer 分区策略
    • Producer 幂等与事务
    • Producer 配置
  • 第5章 消费者与消费组

    • 章节导读
    • Consumer 概述
    • Consumer Group 消费组
    • Consumer 分区分配策略
    • Consumer Offset 提交
    • Consumer 多线程
    • Consumer 配置
  • 第6章 Broker 与控制器

    • 章节导读
    • Broker 概述
    • Broker 配置
    • Controller
    • KRaft 共识协议
  • 第7章 副本与数据可靠性

    • 章节导读
    • 副本机制
    • ISR 与副本同步
    • Leader 选举
    • ACK 与一致性保证
    • 高水位与 Leader Epoch
  • 第8章 存储与性能优化

    • 章节导读
    • 存储架构
    • 日志清理与压缩
    • Page Cache 与零拷贝
    • Producer 性能优化
    • Consumer 性能优化
    • Broker 性能优化
  • 第9章 生产环境运维与监控

    • 章节导读
    • Topic 管理
    • Kafka 运维工具
    • 监控
    • 常见故障排查
  • 第10章 Kafka生态与面试考点

    • 章节导读
    • Kafka 生态全景
    • 面试高频 30 题

存储架构

定义与作用

Kafka 的存储架构是其高性能的核心。Kafka 并非使用 B-Tree 或 LSM-Tree 这类通用存储引擎,而是采用了追加写日志(Append-Only Log)+ 分段(Segment)+ 稀疏索引的专用设计。

这种设计利用了磁盘顺序 I/O 的速度接近内存随机 I/O 这一关键特性,将数据以文件的形式高效持久化。

核心原理

磁盘上的物理结构

文件命名规则:以该 Segment 的起始 Offset 为名(20 位数字,左补零)。

Segment 内部数据格式

文件内容作用
.log消息数据(二进制序列)实际存储
.indexOffset → 文件位置映射(稀疏)快速定位
.timeindex时间戳 → Offset 映射按时间查找
.snapshotLeader Epoch 信息防止数据回滚

稀疏索引与二分查找

稀疏索引的设计哲学:不索引每条消息(那样索引文件会非常大),而是每 log.index.interval.bytes 字节(默认 4096)建一条索引。查找时先二分定位到最近的索引条目,再顺序扫描。这种设计在顺序 I/O 场景下效率极高。

完整示例

示例一:直接浏览 Kafka 磁盘文件

# 1. 查看 log.dirs 中的文件
ls -la /tmp/kraft-logs-1/topic-orders-0/
# -rw-r--r-- 1 user user 1048576000 Jun 12 10:00 00000000000000000000.log
# -rw-r--r-- 1 user user   10485760 Jun 12 10:00 00000000000000000000.index
# -rw-r--r-- 1 user user   10485760 Jun 12 10:00 00000000000000000000.timeindex

# 2. 用 kafka-dump-log.sh 查看日志文件内容
bin/kafka-dump-log.sh --files /tmp/kraft-logs-1/topic-orders-0/00000000000000000000.log
# Dumping /tmp/kraft-logs-1/topic-orders-0/00000000000000000000.log
# Starting offset: 0
# offset: 0 position: 0 CreateTime: 1686... keySize: 3 valueSize: 5
#   payload: key1-value1
# offset: 1 position: 62 CreateTime: 1686... keySize: 3 valueSize: 5
#   payload: key2-value2

示例二:观察 Segment 滚动

# 1. 创建一个低 Segment 大小的 Topic
bin/kafka-topics.sh --create --topic demo-segment \
  --partitions 1 --replication-factor 1 \
  --config segment.bytes=1048576 \  # 1MB
  --bootstrap-server localhost:9092

# 2. 发送大量数据触发 Segment 滚动
for i in $(seq 1 10000); do
  echo "message-$i with lots of padding xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    | bin/kafka-console-producer.sh --topic demo-segment --bootstrap-server localhost:9092
done

# 3. 观察 Segment 文件
ls -la /tmp/kraft-logs-1/demo-segment-0/
# 00000000000000000000.log  (1MB)
# 00000000000000001234.log  (1MB)
# 00000000000000002567.log  (正在写入)

# 4. 查看 Segment 列表
bin/kafka-log-dirs.sh --bootstrap-server localhost:9092 --describe \
  --topic-list demo-segment

操作前后对比:

阶段Segment 文件数说明
初始100000000000000000000.log
写入 ~1300 条后3自动切成两个完整 Segment + 一个活跃 Segment

易错场景

易错 1:log.segment.bytes 设太大

场景:log.segment.bytes=10GB,保留策略按大小。

后果:过期删除最小粒度为 Segment。10GB 的 Segment 意味着每次清理至少释放 10GB,无法精确控制磁盘使用。也影响 kafka-log-dirs.sh 的日志清理效率。

建议:保持在 512MB-1GB,最大不超过 2GB。

易错 2:不同分区共用同一磁盘目录

场景:多个高流量分区的数据存在同一块机械硬盘上。

后果:磁头在多个 Segment 文件的 Appending 间跳动(虽然每个文件内部是顺序 I/O,但文件间是随机的)。

解决:将 log.dirs 设为多个物理磁盘,Kafka 自动在不同磁盘间分布分区。

面试高频考点

Q:Kafka 的存储引擎如何实现 O(1) 的磁盘读写?

A:通过三个设计:

  1. 追加写:不修改已有数据,所有写入都是 O(1) 的磁盘扇区定位
  2. 稀疏索引:内存中保存每个 Segment 的稀疏索引映射,查找时二分定位到最近索引 + 小范围顺序扫描
  3. Page Cache 依赖:不维护自己的内存缓存,直接利用 OS 的 Page Cache。最近写入的数据大概率在缓存中,读命中率极高

代价:随机读取特定 Offset(如回溯消费)可能需要多次磁盘寻道,但这是日志型系统的典型取舍。

上一页
章节导读
下一页
日志清理与压缩