生产者与消费者
1. 这是什么
生产者负责发送消息,消费者负责拉取和处理消息。
这是 Kafka 业务接入层最直接的两个角色。
一句话理解:
- Producer 决定“消息怎么发进去”
- Consumer 决定“消息怎么读出来并处理完”
2. 为什么重要
大多数消息链路问题,都发生在这几个环节:
- 生产发送
- 消费处理
- offset 提交
- 再均衡
理解两端行为,是真正用好 Kafka 的基础。
3. 先建立直觉:发送成功不等于业务完成
一个非常常见的误区是:
- Producer 发送成功了,链路就万事大吉
其实远远不是。
真正的业务完成,还取决于:
- 消费者是否真的处理成功
- offset 是否按预期提交
- 失败后是否会重复处理或漏处理
4. 核心内容
4.1 生产发送流程
生产者的核心工作不只是“发消息”,还包括:
- 序列化
- 选择分区
- 发送确认
- 重试控制
4.2 分区选择策略
生产者通常需要决定:
- 消息进入哪个分区
这通常和:
- key
- 分区策略
密切相关。
4.3 消费拉取流程
消费者的核心流程通常是:
- 拉取消息
- 执行业务处理
- 提交 offset
这三步的顺序和策略,会直接影响:
- 是否重复消费
- 是否漏消费
4.4 自动提交和手动提交
自动提交的优点是:
- 简单
但风险是:
- 业务还没处理成功,offset 可能已经提交
手动提交更灵活,因为你可以在:
- 真正处理成功后再提交
4.5 消费组再均衡
当这些情况发生时,消费组通常会再均衡:
- 新消费者加入
- 消费者下线
- 分区数变化
再均衡的代价是:
- 分区归属变动
- 短时间消费抖动
5. 学习重点
这一章最重要的是掌握:
- 发送成功不等于业务处理完成
- 自动提交和手动提交 offset 的语义差别很大
- 再均衡会影响消费稳定性
- 生产端和消费端要分别考虑可靠性
6. 常见问题
6.1 只关注发消息,不关注消费端语义
这会让消息链路看起来“很通”,但业务语义并不稳。
6.2 自动提交导致消息处理不一致
这是非常高频的消费语义坑。
6.3 消费组变动时忽视再均衡成本
消费并发扩展不是没有代价的。
7. 动手验证
当前环境没有 Kafka CLI,这里用纯 Java demo 直接验证“自动提交”和“手动提交”两种心智差异。
7.1 准备一个可运行示例
新建文件 KafkaConsumerSemanticsDemo.java,内容如下:
java
import java.util.ArrayList;
import java.util.List;
public class KafkaConsumerSemanticsDemo {
static class Record {
final long offset;
final String value;
Record(long offset, String value) {
this.offset = offset;
this.value = value;
}
}
public static void main(String[] args) {
List<Record> partition = new ArrayList<>();
partition.add(new Record(0, "msg-0"));
partition.add(new Record(1, "msg-1"));
long autoCommittedOffset = 0;
try {
Record r = partition.get(0);
autoCommittedOffset = r.offset + 1; // 先提交
throw new RuntimeException("business fail");
} catch (Exception e) {
System.out.println("autoCommitLostRisk=true");
System.out.println("autoCommittedOffset=" + autoCommittedOffset);
}
long manualCommittedOffset = 0;
try {
Record r = partition.get(0);
throw new RuntimeException("business fail");
} catch (Exception e) {
System.out.println("manualCommitRetryPossible=true");
System.out.println("manualCommittedOffset=" + manualCommittedOffset);
}
manualCommittedOffset = 1;
System.out.println("manualCommittedAfterSuccess=" + manualCommittedOffset);
}
}7.2 编译并运行
bash
javac KafkaConsumerSemanticsDemo.java
java KafkaConsumerSemanticsDemo7.3 你应该观察到什么
text
autoCommitLostRisk=true
autoCommittedOffset=1
manualCommitRetryPossible=true
manualCommittedOffset=0
manualCommittedAfterSuccess=17.4 每一行在验证什么
autoCommittedOffset=1:说明自动提交可能在业务失败前就推进 offsetmanualCommittedOffset=0:说明手动提交让失败消息仍然有重试机会manualCommittedAfterSuccess=1:说明处理成功后再提交 offset,语义更可控
8. 练习建议
- 写一个简单生产消费 demo
- 对比自动提交和手动提交 offset
- 记录一次消费组再均衡过程
- 总结“发送成功”和“处理成功”的区别
9. 自测问题
- 自动提交 offset 有什么风险?
- 再均衡为什么会影响消费稳定性?
- 生产端和消费端应该分别关注哪些可靠性问题?
- 为什么说发送成功不等于业务完成?
10. 自测核对要点
- Producer 成功发送只是消息进入链路的一部分
- Consumer 的处理和 offset 提交顺序非常关键
- 自动提交简单,但语义风险更高
- 再均衡会带来消费抖动和分区重分配