Kafka11-知识补充
kafka知识补充
文章目录
- kafka知识补充
- @[toc]
- 1-知识整理
- 1-Kafka的HW是什么意思,和Mysql的MVVC并发设计有没有类似的地方
- ✅ Kafka 的 HW 是什么?
- ✅ MySQL 的 MVCC 是什么?
- ❓有没有类似的地方?
- 📌 举个例子
- ✅ 结论
- 2-Kafka的HW和LEO之间的数据是不是可以认为未完成ACK还不能对外进行数据暴露
- ✅ 关键点解析:
- ✅ 与 ACK 的关系:
- ✅ 总结:
- 3-kafka的controller的选举在ZAB和kRaft的区别
- ✅ 1. 依赖的外部系统
- ✅ 2. 选举协议与一致性模型
- ✅ 3. 元数据存储与管理方式
- ✅ 4. 故障恢复与性能表现
- ✅ 5. 总结:核心区别速览
- 📌 结论:
- 4-Kafka的数据偏移量是做什么的
- 5-Kafka的segment工作机制
- 一、Segment 的作用
- 二、Segment 的工作机制
- 1. **Segment 文件结构**
- 2. **Segment 的创建与滚动(Rolling)**
- 3. **写入流程**
- 4. **查找流程**
- 5. **清理机制**
- 三、总结
- 6-kafka的partion是如何利用稀疏索引进行跳表定位到segment的
- 一、segment 文件命名与组织
- 二、稀疏索引结构
- 三、跳表定位 segment 过程
- 四、小结
- 7-kakfa为什么可以使用到pageCache原因
文章目录
- kafka知识补充
- @[toc]
- 1-知识整理
- 1-Kafka的HW是什么意思,和Mysql的MVVC并发设计有没有类似的地方
- ✅ Kafka 的 HW 是什么?
- ✅ MySQL 的 MVCC 是什么?
- ❓有没有类似的地方?
- 📌 举个例子
- ✅ 结论
- 2-Kafka的HW和LEO之间的数据是不是可以认为未完成ACK还不能对外进行数据暴露
- ✅ 关键点解析:
- ✅ 与 ACK 的关系:
- ✅ 总结:
- 3-kafka的controller的选举在ZAB和kRaft的区别
- ✅ 1. 依赖的外部系统
- ✅ 2. 选举协议与一致性模型
- ✅ 3. 元数据存储与管理方式
- ✅ 4. 故障恢复与性能表现
- ✅ 5. 总结:核心区别速览
- 📌 结论:
- 4-Kafka的数据偏移量是做什么的
- 5-Kafka的segment工作机制
- 一、Segment 的作用
- 二、Segment 的工作机制
- 1. **Segment 文件结构**
- 2. **Segment 的创建与滚动(Rolling)**
- 3. **写入流程**
- 4. **查找流程**
- 5. **清理机制**
- 三、总结
- 6-kafka的partion是如何利用稀疏索引进行跳表定位到segment的
- 一、segment 文件命名与组织
- 二、稀疏索引结构
- 三、跳表定位 segment 过程
- 四、小结
- 7-kakfa为什么可以使用到pageCache原因
1-知识整理
1-Kafka的HW是什么意思,和Mysql的MVVC并发设计有没有类似的地方
Kafka 的 HW(High Watermark,高水位)和 MySQL 的 MVCC(多版本并发控制)在设计目标和效果上有一些表面相似之处,但本质机制完全不同,不能简单类比。
✅ Kafka 的 HW 是什么?
HW 是 Kafka 中分区级别的一个偏移量标记,表示:
所有 ISR(同步副本)都已经复制完成的最大偏移量。
-
消费者只能消费 HW 之前的消息。
-
HW 由 Leader 副本维护,更新规则是:
HW = min(Leader LEO, 所有 ISR 副本的 LEO)
这意味着 HW 是所有副本中同步进度最慢的那个副本的偏移量,也就是“木桶理论”中的最短木板。
✅ MySQL 的 MVCC 是什么?
MVCC 是 MySQL(尤其是 InnoDB)用来实现事务隔离级别的机制,通过:
- 为每行记录保存多个版本(通过
trx_id
和roll pointer
) - 每个事务在启动时获取一个一致性视图(Read View)
- 根据事务的隔离级别,判断哪个版本对当前事务可见
从而实现非阻塞读(快照读),避免读写冲突。
❓有没有类似的地方?
对比维度 | Kafka HW | MySQL MVCC |
---|---|---|
目的 | 保证副本间数据一致性 | 保证事务间读写隔离性 |
机制 | 基于副本同步进度的偏移量限制 | 基于版本链 + Read View的可见性判断 |
是否多版本 | ❌ 不涉及多版本 | ✅ 每行记录多个版本 |
是否阻塞读写 | ✅ 消费者不能读 HW 之后的数据 | ✅ 写不阻塞读(快照读) |
是否可回滚 | ✅ 副本故障时会截断 HW 之后的数据 | ✅ 事务回滚时丢弃未提交版本 |
是否可见性控制 | ✅ 消费者只能看到 HW 之前的数据 | ✅ 事务只能看到符合隔离级别的版本 |
✅ 总结一句话:
Kafka 的 HW 是副本同步的“安全线”,MySQL 的 MVCC 是事务可见性的“时间线”。
它们都限制了“你能看到什么”,但一个是为了容灾一致,一个是为了并发隔离。
📌 举个例子
- Kafka:Leader 有 10 条消息,但 HW 是 7,说明只有前 7 条是所有副本都有的,消费者只能读到 7。
- MySQL:事务 A 插入了 id=5 的记录但未提交,事务 B 查询时通过 MVCC 看不到这条记录,因为它还在“未来”。
✅ 结论
Kafka 的 HW 和 MySQL 的 MVCC 没有机制上的相似性,但在效果上都起到了“限制可见性”的作用。
一个是为了副本一致性,一个是为了事务隔离性。
2-Kafka的HW和LEO之间的数据是不是可以认为未完成ACK还不能对外进行数据暴露
你的理解基本正确,但可以更严谨一些:
在 Kafka 中,HW(High Watermark)与 LEO(Log End Offset)之间的数据确实不能被消费者消费,也就是说,这部分数据对外不可见。原因如下:
✅ 关键点解析:
- LEO(Log End Offset):表示副本日志中下一条待写入消息的 offset,即当前日志的“末端”。
- HW(High Watermark):表示已提交消息的最大 offset,即消费者可以消费到的最新消息位置。
- 消费者只能消费到 HW 之前的数据,HW 之后(即 HW 到 LEO 之间)的数据尚未被提交,因此对消费者不可见。
✅ 与 ACK 的关系:
- 当
acks=all
时,只有所有 ISR 中的副本都写入了消息,该消息才会被提交,HW 才会推进。 - 在消息被提交(即 HW 推进)之前,即使 Leader 已经写入(LEO 已更新),这条消息也不会被消费者看到,因为 Kafka 保证的是已提交消息的一致性。
✅ 总结:
HW 与 LEO 之间的数据,确实可以认为是“未完成 ACK”或“未提交”的数据,Kafka 不会将其暴露给消费者。
这种机制是 Kafka 实现高可用与数据一致性的关键设计之一。
3-kafka的controller的选举在ZAB和kRaft的区别
Kafka controller 的选举机制在 ZAB(ZooKeeper Atomic Broadcast)与 KRaft 模式下的核心区别,体现在依赖系统、选举协议、元数据存储位置、一致性模型以及故障恢复效率等多个方面,具体对比如下:
✅ 1. 依赖的外部系统
特性 | ZAB(ZooKeeper)模式 | KRaft 模式 |
---|---|---|
是否依赖外部系统 | ✅ 依赖 ZooKeeper 集群 | ❌ 不依赖外部系统,Kafka 自管理元数据 |
控制器选举由谁负责 | ZooKeeper 通过创建临时节点选举 controller | Kafka 内部通过 Raft 协议选举 active controller |
在 ZooKeeper 模式下,Kafka 的 controller 是通过抢占 ZooKeeper 中的
/controller
临时节点来选举的;而 KRaft 模式则由一组 controller 节点组成 Raft quorum,自主选举出 leader(即 active controller)。
✅ 2. 选举协议与一致性模型
特性 | ZAB 模式 | KRaft 模式 |
---|---|---|
使用的协议 | ZAB(ZooKeeper Atomic Broadcast) | Raft(Kafka 实现版本) |
一致性模型 | 最终一致性(ZooKeeper 保证) | 强一致性(Raft 日志复制) |
控制器选举方式 | 抢占临时节点,非分布式投票 | Raft 多数派投票,日志最新的候选者才能当选 |
KRaft 模式下的 controller 选举基于 Raft 协议,只有日志最新且获得多数票的节点才能成为 active controller,这避免了“脑裂”问题,并提升了选举的可靠性。
✅ 3. 元数据存储与管理方式
特性 | ZAB 模式 | KRaft 模式 |
---|---|---|
元数据存储位置 | ZooKeeper 的 znode 中 | Kafka 内部的 __cluster_metadata topic |
元数据格式 | 非日志结构,分散存储 | 日志结构(log-based),顺序写入 |
元数据同步方式 | 通过 ZooKeeper 通知 | 通过 MetadataFetch API 拉取日志 |
KRaft 模式将元数据作为 Kafka 的一个内部 topic 存储,所有 broker 通过拉取方式同步元数据,提升了可扩展性和一致性。
✅ 4. 故障恢复与性能表现
特性 | ZAB 模式 | KRaft 模式 |
---|---|---|
故障恢复速度 | 慢(需重新注册 ZooKeeper) | 快(通过 replay 元数据日志恢复) |
元数据传播延迟 | 高(ZooKeeper 通知机制) | 低(Kafka 内部日志复制) |
大规模集群支持 | 有限(ZooKeeper 成为瓶颈) | 更好(支持更多分区和 broker) |
在大规模集群中,ZooKeeper 容易成为性能瓶颈,而 KRaft 模式通过日志化元数据和分布式 Raft 协议,显著提升了元数据处理的吞吐和恢复速度。
✅ 5. 总结:核心区别速览
维度 | ZAB(ZooKeeper) | KRaft |
---|---|---|
控制器选举机制 | 抢占临时节点 | Raft 多数派投票 |
一致性保障 | 最终一致性 | 强一致性 |
元数据存储 | ZooKeeper | Kafka 内部 topic |
故障恢复 | 慢 | 快 |
外部依赖 | 依赖 ZooKeeper | 无外部依赖 |
可扩展性 | 有限 | 更好 |
📌 结论:
Kafka 在 ZAB 模式下依赖 ZooKeeper 进行 controller 选举,机制简单但存在一致性弱、恢复慢、扩展性差等问题;
而在 KRaft 模式下,通过内置的 Raft 协议实现 controller 选举,具备强一致性、更快的故障恢复、更高的可扩展性,是 Kafka 未来发展的主流方向。
4-Kafka的数据偏移量是做什么的
在 Kafka 里,“数据偏移量”(offset)是 一条消息在某个分区内独一无二的"身份证号"。
它从 0 开始,严格单调递增,用来回答"这条消息在分区里排第几位"这个问题。
消费者靠它知道自己"读到哪里",Kafka 靠它保证"同一条消息只被算一次"。
具体描述可以拆成 5 句话:
- 作用域:offset 只在 单个分区 内有效,不同分区的 offset 彼此无关。
- 唯一性:分区里第 N 条消息的 offset 就是 N-1(第一条是 0,第二条是 1……)。
- 不可变性:消息一旦写入,offset 就永久绑定,不会重写、不会跳跃。
- 消费进度:消费者把"下一次要读的 offset"作为 checkpoint 提交给 Kafka(或 Zookeeper/__consumer_offsets 主题),重启后从该位置继续,实现断点续传。
- 重放与幂等:手动把 offset 改小就能重新消费旧数据;由于 offset 唯一,Kafka 可保证"同一 offset 读取到的永远是同一条消息",从而支持幂等计算。
一句话总结:offset 是 Kafka 在分区内给消息编的"序号",既是消费者账本,也是 Kafka 本身实现顺序、持久、可重放的核心机制。
5-Kafka的segment工作机制
Kafka 的 Segment(日志段) 是其存储机制的核心组件,用于将每个 Partition 的日志文件进一步细分为多个更小、可管理的物理文件段,以提升读写效率、简化清理策略并优化磁盘利用率。以下是 Segment 的作用及其工作机制的详细说明:
一、Segment 的作用
-
避免单文件过大
Kafka 每个 Partition 是一个逻辑上的日志文件,如果不分段,随着消息不断写入,该文件会无限增长,带来管理和清理上的困难。通过将日志切分为多个 Segment,Kafka 可以更高效地管理磁盘空间。 -
支持高效清理策略
Kafka 支持基于时间或大小的日志保留策略,Segment 是清理操作的最小单位。旧的 Segment 可以被整体删除,避免逐条删除带来的性能开销。 -
提高读写性能
每个 Segment 配有索引文件(.index
和.timeindex
),支持基于偏移量或时间戳的快速查找,提升消费效率。 -
支持压缩(Compaction)机制
对于启用压缩的 Topic,Kafka 会在 Segment 层面进行合并,仅保留每个 Key 的最新消息,节省存储空间。
二、Segment 的工作机制
1. Segment 文件结构
每个 Segment 包含以下三类文件:
文件类型 | 作用说明 |
---|---|
.log | 存储实际的消息数据 |
.index | 偏移量索引文件,记录消息偏移量到物理位置的映射 |
.timeindex | 时间戳索引文件,记录时间戳到偏移量的映射(用于时间范围查找) |
这些文件以 Segment 的起始偏移量命名,例如:00000000000000000000.log
、00000000000000000000.index
。
2. Segment 的创建与滚动(Rolling)
Kafka 会按照以下规则创建新的 Segment:
- 大小限制:当前 Segment 大小达到
log.segment.bytes
(默认 1GB)时,创建新 Segment。 - 时间限制:即使未达大小限制,超过
log.roll.ms
或log.roll.hours
(默认 7 天)也会创建新 Segment。 - 索引间隔:当消息偏移量或时间戳索引间隔达到一定字节数(如 4KB)时,也可能触发新 Segment 的创建。
3. 写入流程
- 所有消息追加写入当前活跃的 Segment(Active Segment)。
- 同时更新
.index
和.timeindex
文件,记录稀疏索引(默认每 4KB 数据建一个索引项)。 - 当满足滚动条件时,关闭当前 Segment,创建新的 Active Segment。
4. 查找流程
- 消费者根据偏移量查找消息时,Kafka 先定位到对应的 Segment。
- 利用
.index
文件进行二分查找,找到最近的索引项。 - 从
.log
文件中顺序扫描,找到目标消息。
5. 清理机制
Kafka 支持两种清理策略:
策略类型 | 描述 |
---|---|
删除(Delete) | 根据时间(log.retention.hours )或大小(log.retention.bytes )删除旧 Segment |
压缩(Compact) | 保留每个 Key 的最新消息,旧版本消息被清理,适用于状态类数据(如配置、用户信息) |
压缩过程会合并多个 Segment,生成新的 Segment 并替换旧的,最终删除旧 Segment。
三、总结
Kafka 的 Segment 机制通过将大日志文件切分为多个小段,实现了:
- 高效写入:顺序追加 + 批量刷盘 + 内存映射
- 快速读取:稀疏索引 + 二分查找
- 灵活管理:基于时间/大小的清理策略
- 存储优化:压缩机制节省空间
这种设计是 Kafka 能处理高吞吐量、大规模数据流的关键基础之一。
6-kafka的partion是如何利用稀疏索引进行跳表定位到segment的
Kafka 的 partition 在利用稀疏索引进行跳表定位到 segment 时,主要经历了以下关键步骤:
一、segment 文件命名与组织
每个 partition 目录下包含多个 segment 文件,每个 segment 文件由三种文件组成:
.log
文件:存储实际消息数据;.index
文件:偏移量索引文件,采用稀疏索引结构;.timeindex
文件:时间戳索引文件,用于按时间定位消息。
segment 文件以该 segment 中第一条消息的 offset 命名,固定为 20 位数字,例如:
00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
这种命名方式确保了 segment 文件按 offset 有序排列,为跳表(二分查找)提供了基础 。
二、稀疏索引结构
Kafka 的 .index
文件采用稀疏索引(sparse index)结构,并不为每条消息都建立索引,而是每隔一定字节数(由 log.index.interval.bytes
参数控制,默认 4KB)才记录一条索引项 。
每个索引项包含两个字段:
- relativeOffset(4 字节):相对于该 segment 起始 offset 的相对偏移量;
- position(4 字节):该消息在
.log
文件中的物理位置(字节偏移量)。
例如,索引项结构为:
relativeOffset | position |
---|---|
0 | 0 |
100 | 1024 |
200 | 4096 |
这种稀疏索引结构显著减少了索引文件大小,使其可以全部加载到内存中,提高查找效率 。
三、跳表定位 segment 过程
当消费者或副本需要根据 offset 查找消息时,Kafka 首先通过跳表(二分查找)定位到对应的 segment 文件:
-
确定目标 offset:例如 offset = 368776。
-
二分查找 segment 文件列表:
- 所有 segment 文件按起始 offset 排序;
- 通过二分查找快速确定目标 offset 落在哪个 segment 文件范围内。
例如,假设存在以下 segment 文件:
00000000000000000000.index (起始 offset = 0) 00000000000000368769.index (起始 offset = 368769) 00000000000000737337.index (起始 offset = 737337)
对于 offset = 368776,二分查找会定位到第二个 segment 文件(起始 offset = 368769),因为:
368769 ≤ 368776 < 737337
因此,目标消息位于
00000000000000368769.log
文件中 。
四、小结
Kafka partition 利用稀疏索引进行跳表定位 segment 的核心机制为:
- segment 文件按起始 offset 命名并排序,为跳表提供有序基础;
- 稀疏索引结构减少索引文件大小,提高内存加载效率;
- 通过二分查找(跳表)快速定位目标 offset 所在的 segment 文件,避免顺序扫描,提高查找效率。
这种设计在保证高效查找的同时,显著降低了内存和磁盘开销,是 Kafka 高吞吐、高性能的重要基础 。
7-kakfa为什么可以使用到pageCache原因
Kafka 之所以能把 PageCache 用到极致,根本不是因为“非实时落盘”,而是因为:
- 消息顺序追加写,使得 PageCache 里的数据几乎全是连续页面,命中后预读/批量刷盘效率极高;
- 消息生产完立刻被消费(时间局部性),99 % 的读请求直接命中 PageCache,磁盘 I/O 被跳过;
- 通过 sendfile 零拷贝,把 PageCache 里的页面直接 DMA 到网卡,不经过用户态内存,一条消息从内存到网络只有 2 次拷贝、0 次 CPU 复制;
- 复用操作系统 LRU、刷盘线程、崩溃回收机制,Kafka 自己不用写缓存管理代码,既省内存又避免 GC 和进程崩溃丢数据。
换句话说,PageCache 是 Kafka 高吞吐的“加速器”,而“异步落盘”只是操作系统对 PageCache 的通用刷盘策略,并非 Kafka 选择 PageCache 的理由。