Apache Kafka
Kafka 的后端工程主笔记:从 Topic/Partition/Offset、Producer/Consumer Group、复制与 KRaft,到投递语义、重放、顺序、积压、事务和典型选型边界。
[!info] related notes
Apache Kafka
[!abstract] 一句话定位 Kafka 是分布式、持久化、可重放的事件日志平台。Producer 向 Topic 的 Partition 追加 Record,Consumer 通过 Offset 独立记录读取进度;它的核心不是“发完即删的队列”,而是保留事件历史供多个下游按自己的节奏消费和重放。
核心数据模型
Topic
├─ Partition 0: offset 0, 1, 2, ...
├─ Partition 1: offset 0, 1, 2, ...
└─ Partition 2: offset 0, 1, 2, ...
| 对象 | 作用 | 关键边界 |
|---|---|---|
| Broker | 存储 Partition 并服务读写 | 单个节点不是整个集群 |
| Topic | 事件流的逻辑名称 | 由多个 Partition 组成 |
| Partition | 顺序日志、扩展和并行边界 | 不提供跨 Partition 全局顺序 |
| Record | Key、Value、Headers、Timestamp | Key 常影响分区 |
| Offset | Record 在某 Partition 中的位置 | 只在对应 Partition 内有意义 |
| Consumer Group | 一组协作消费者 | 每组独立维护消费进度 |
Producer 写入链路
Application
→ Serialize Record
→ Choose Partition
→ Batch + Compress
→ Partition Leader
→ Replicate to Followers
→ Acknowledge Producer
Partition Key
要求同一业务实体保持局部顺序时,常用 order_id、user_id 等稳定 Key 进入同一 Partition。
代价是高频 Key 可能形成 Hot Partition。顺序、均衡和可扩展性需要一起权衡。
Batch 与 Compression
Kafka 通过 Append Log、批处理、顺序 I/O、压缩和 Partition 并行获得高吞吐。批次更大通常提升吞吐,但也可能增加等待和端到端延迟。
ACK 的含义
Producer 返回成功代表什么,取决于 ACK、复制和 Broker 配置。不要只背参数,要回答:
消息到达 Leader 即算成功?
还是达到足够副本后才算成功?
Leader 故障后,已确认消息还能否保留?
Replication、Leader 与 ISR
Partition 的副本由一个 Leader 和若干 Followers 组成:
Partition P0
├─ Leader Replica
├─ Follower Replica
└─ Follower Replica
Producer 写 Leader,Consumer 通常从 Leader 读取;Followers 复制日志。
ISR 是当前与 Leader 保持足够同步、具备可靠接管资格的副本集合。ISR 缩小、Under-replicated Partition 增多通常是 Broker、磁盘或网络健康问题。
Partition count → parallelism and distribution
Replication factor → redundancy and failure tolerance
KRaft:现代 Kafka 元数据层
Kafka 4.x 仅支持 KRaft 模式,不再支持 ZooKeeper 模式。KRaft 使用 Controller Quorum 维护:
- Broker / Topic / Partition metadata;
- Controller election;
- Cluster metadata log。
因此现代学习路径应是:
Brokers + KRaft Controller Quorum
ZooKeeper 只用于理解旧集群和迁移历史,不再是新 Kafka 架构的默认组成。
Consumer Group 与并行度
Topic: 4 Partitions
Consumer Group A:
C1 → P0, P1
C2 → P2, P3
传统 Consumer Group 中,一个 Partition 在同一时刻通常只由组内一个 Consumer 处理。因此 Partition 数量是该组并行度的重要上限;Consumer 多于 Partition 时会有实例空闲。
不同 Consumer Group 各自维护 Offset,所以库存、分析、通知等下游可以独立消费同一事件流。
Offset Commit 与故障窗口
Consumer Position 表示下一条将读取的位置;Committed Offset 是重启或 Rebalance 后恢复进度的依据。
先处理业务,再提交 Offset
process record
→ write DB succeeds
→ crash before offset commit
→ record delivered again
结果:可能重复,通常不容易静默丢业务处理。常见组合是:
At-least-once + Idempotent Consumer
先提交 Offset,再处理业务
commit offset
→ crash before DB write
结果:记录可能不会再次交付,业务效果丢失。
提交的 Offset 通常应表示“下一条待处理记录”,并与业务处理边界一起设计。
Rebalance
Consumer 加入、退出、超时或 Partition 变化时,Group 需要重新分配 Partition。
Rebalance 期间可能暂停消费,并引入:
- 重复处理;
- 未提交进度;
- 状态迁移;
- 延迟抖动。
消费者应及时 poll、正确处理 revoke / assignment,并让业务操作可幂等。
Retention、Replay 与 Compaction
Retention
Kafka 根据时间或大小保留日志。Consumer 读取后,Record 不会因为 ACK 而立即删除。
Replay
Consumer 可以重置 Offset,重新读取保留期内的历史事件,用于:
- 修复后重算;
- 新下游补历史;
- 审计与回放;
- 构建派生视图。
Log Compaction
Compacted Topic 按 Key 保留较新的状态记录,用于状态重建或 Changelog。它不是普通时间保留策略的同义词,也不保证物理上只剩一条 Record。
Ordering 的真实边界
Kafka 保证的是 Partition 内日志顺序,不是整个 Topic 的全局顺序。
即使 Record 按序读取,并发处理、异步提交和失败重试也可能让最终业务效果乱序。要求同一实体顺序时,应同时约束:
- Key → Partition;
- Consumer 处理模型;
- Retry 路径;
- 下游状态版本。
Delivery Semantics 与 Exactly-once
Kafka 的 idempotent producer 和 transaction 能在 Kafka 内部构建更强的处理语义,例如原子写入多个 Topic/Partition 和 Offset。
[!warning] 系统边界 Kafka Transaction 不会自动把外部 PostgreSQL、Redis、邮件或支付 API 纳入同一原子事务。跨系统仍需要幂等、唯一约束、Outbox、CDC 或补偿。
适用场景
- 数据库 CDC;
- 领域事件总线;
- 行为、日志、指标和 telemetry;
- 多下游独立消费;
- 需要长期 Retention 与 Replay;
- Stream Processing。
不一定适合
- 很小的系统和极少量后台任务;
- 主要需求是复杂 routing、逐条 Retry / DLQ 的 Work Queue;
- 强依赖全局顺序;
- 团队无法承担 Partition、容量、Schema 和运维复杂度。
BodySense 当前边界
BodySense 当前运行时代码、依赖和部署配置中没有 Kafka。当前相关能力采用更简单的组件:
Background Job
→ PostgreSQL-backed JobRuntime / JobRepository
Agent runtime history
→ PostgreSQL Runtime Event Log
Live browser delivery
→ SSE
Auth/session/rate limit
→ Redis
也就是说,目前没有:
Kafka Broker
Kafka client dependency
Kafka Topic / Producer / Consumer Group
Kafka deployment service
这并不是缺陷。BodySense 当前规模下,把 Kafka 仅仅为了“学习中间件”塞进生产架构,会增加 Broker、Partition、Schema、Lag、Rebalance 和运维成本,却没有清晰业务收益。
学习 Kafka 更适合使用独立实验环境:Producer → 多 Partition Topic → 两个 Consumer Group → Offset Commit → 故障重放 → 幂等消费。等未来真的出现 CDC、多独立下游、长期事件 Replay 或高吞吐事件总线需求,再评估是否进入 BodySense。
生产故障与观测
| 信号 | 可能原因 |
|---|---|
| Consumer Lag 上升 | 生产加快、消费变慢、Rebalance、Hot Partition |
| ISR Shrink / Under-replicated | Broker、网络、磁盘或复制异常 |
| Frequent Rebalance | Consumer 不稳定、poll 超时、部署抖动 |
| Disk 快速增长 | Retention、吞吐、Compaction 或容量配置 |
| Producer Timeout | Broker 压力、网络、ACK / ISR 条件 |
| Uneven Partition Load | Key 分布不均、Partition 设计问题 |
至少观察吞吐、请求延迟、错误率、Consumer Lag、ISR、Rebalance、磁盘、网络和 Controller Quorum 健康。
面试掌握标准
- Topic / Partition / Offset / Broker;
- Producer ACK、Replication、Leader、ISR;
- Consumer Group、并行度和 Rebalance;
- Offset Commit 的两个故障窗口;
- Retention、Replay 与 Compaction;
- Partition 内顺序与业务效果顺序;
- Kafka exactly-once 的系统边界;
- KRaft 与旧 ZooKeeper 架构的区别。
官方资料
- Kafka documentation: https://kafka.apache.org/documentation/
- Kafka 4.0 release / KRaft-only milestone: https://kafka.apache.org/blog/2025/03/18/apache-kafka-4.0.0-release-announcement/
- Consumer API / offsets: https://kafka.apache.org/documentation/#consumerapi