本文是大数据系列第 53 篇,深入拆解 Kafka 三大核心组件的工作原理与协作流程。
整体架构回顾
Kafka 是一个分布式发布-订阅消息系统,三大核心角色分工明确:
Producer(生产者)
↓ 发布消息
Broker 集群(消息存储与路由)
↓ 消费消息
Consumer Group(消费者组)
三者通过 Topic + Partition 解耦:Producer 只管发布,Consumer 只管订阅,Broker 负责中间的持久化与路由。
Producer:消息生产者
基本职责
Producer 负责创建消息并发布到指定 Topic。发送流程:
- 序列化消息(Key/Value)
- 根据分区策略选择目标 Partition
- 将消息追加到本地缓冲区(
RecordAccumulator) - 后台 Sender 线程批量发送到对应 Broker
分区策略
| 策略 | 触发条件 | 效果 |
|---|---|---|
| 指定分区 | 发送时显式指定 partition | 精确路由 |
| Hash 分区 | 指定消息 Key | 相同 Key 始终写同一 Partition,保证局部有序 |
| 轮询分区 | 无 Key 时默认 | 均匀分布,最大化吞吐 |
| 自定义分区器 | 实现 Partitioner 接口 | 业务自定义路由逻辑 |
ACK 确认机制
acks 参数控制消息可靠性与吞吐的权衡:
| acks 值 | 语义 | 适用场景 |
|---|---|---|
0 | 不等待任何确认,即发即忘 | 日志收集,允许少量丢失 |
1 | Leader 写入成功即确认 | 默认值,均衡可靠性与性能 |
all(-1) | 所有 ISR 副本写入后确认 | 金融、订单等核心数据 |
异步发送示例
ProducerRecord<Integer, String> record =
new ProducerRecord<>("my_topic", 0, 42, "hello kafka");
// 异步发送,通过回调处理结果
producer.send(record, (metadata, exception) -> {
if (exception == null) {
System.out.println("Sent to partition " + metadata.partition()
+ " at offset " + metadata.offset());
} else {
exception.printStackTrace();
}
});
Broker:消息存储节点
核心职责
Broker 是 Kafka 集群的基本单元,每个 Broker 是一个独立 JVM 进程,负责:
- 接收 Producer 写入的消息,持久化到本地磁盘
- 响应 Consumer 的拉取请求
- 维护 Partition 的 Leader/Follower 角色
- 与 ZooKeeper(或 KRaft)协调集群元数据
Partition 的物理存储
每个 Partition 对应磁盘上的一个目录,内部由多个 Segment 文件组成:
/var/kafka-logs/my_topic-0/
├── 00000000000000000000.log ← 消息数据文件
├── 00000000000000000000.index ← 偏移量稀疏索引
└── 00000000000000000000.timeindex ← 时间戳索引
- 文件名是该 Segment 起始 Offset 的 20 位补零数字
- 写入时 Append-only,读取时通过二分查找索引定位 Offset
- 默认单个 Segment 超过 1GB 或 7 天后滚动生成新 Segment
Leader 与 Follower
Partition Leader(在某个 Broker 上)
← 接收 Producer 写入
→ 响应 Consumer 读取
→ 异步推送给 Follower 同步
Partition Follower(在其他 Broker 上)
→ 从 Leader 拉取消息,追上 Leader 进度
→ 进入 ISR 列表
→ Leader 故障时,从 ISR 中选举新 Leader
Controller 角色
集群中有且仅有一个 Broker 担任 Controller,通过 ZooKeeper 选举产生:
- 监控 Broker 存活状态
- 负责 Partition Leader 选举
- 管理 Partition 的 ISR 列表变更
- 协调新 Broker 加入时的 Partition 重新分配
Consumer:消息消费者
Consumer Group 机制
Kafka 通过 Consumer Group 实现两种消费语义:
同一 Group 内: 不同 Group 间:
Partition 1 → Consumer A Group A → 各自消费
Partition 2 → Consumer B Group B → 各自消费
Partition 3 → Consumer C (发布-订阅语义)
(点对点语义)
关键规则:
- 每个 Partition 在同一 Consumer Group 内只能被一个 Consumer 消费
- Consumer 数量超过 Partition 数时,多余的 Consumer 闲置
- Consumer 退出/加入时触发 Rebalance,重新分配 Partition
Offset 管理
Consumer 通过 Offset 跟踪消费进度:
| 方式 | 说明 |
|---|---|
| 自动提交 | enable.auto.commit=true,每隔 auto.commit.interval.ms 自动提交 |
| 手动同步提交 | consumer.commitSync(),确保消费成功后提交,避免消息丢失 |
| 手动异步提交 | consumer.commitAsync(),性能更高,但失败时不重试 |
Offset 存储在 Kafka 内部 Topic __consumer_offsets 中(Kafka 0.9+ 之后不再依赖 ZooKeeper)。
消费位置重置
通过 auto.offset.reset 控制消费者首次启动或 Offset 丢失时的行为:
earliest:从 Partition 最早的消息开始消费latest(默认):只消费启动后新产生的消息none:不存在已提交 Offset 时抛出异常
Rebalance 触发条件
触发 Rebalance 的情形:
1. Consumer 加入 Group(新实例上线)
2. Consumer 离开 Group(崩溃或正常下线)
3. Consumer 超时未发送心跳(session.timeout.ms)
4. Topic Partition 数量变化
Rebalance 期间所有消费者暂停消费,生产环境应合理配置 session.timeout.ms 和 max.poll.interval.ms 减少不必要的 Rebalance。
消息全流程梳理
1. Producer 序列化消息,选定 Partition
2. Producer 将消息批量发送到目标 Broker(Leader)
3. Leader Broker 将消息写入本地日志(.log 文件)
4. Follower 主动从 Leader 拉取新消息,写入本地副本
5. ISR 中所有副本确认写入后,消息视为"已提交"
6. Consumer 向 Leader 发起 Poll 请求,携带当前 Offset
7. Leader 返回从该 Offset 开始的消息批次
8. Consumer 处理完成后提交新 Offset
小结
- Producer 的分区策略和 ACK 机制决定消息路由和可靠性
- Broker 的 Segment 存储和 ISR 机制保障高性能持久化和高可用
- Consumer Group 通过 Partition 独占分配实现并行消费,Offset 管理控制消费语义
- 三者协同,构成 Kafka 高吞吐、低延迟、高可用的完整闭环