2. Kafka 架构与消息流:Producer、Broker、Consumer、Topic、Partition、Offset 核心概念
要排查消息丢失,你得先搞清楚 Kafka 到底是怎么把消息从 A 搬到 B 的。说白了,Kafka 就是一个分布式的消息系统,核心就三块:生产者、服务端、消费者。我见过不少同事,上来就调参数,结果连消息在哪个环节丢的都没搞明白。嗯,咱们先把这几个核心角色理清楚。
2.1 整体架构:一条消息的旅程
一条消息从产生到被消费,会经过下面这些节点。我习惯把这个流程叫做「消息的生命周期」。
核心流程: Producer → Broker (Topic → Partition) → Consumer
2.2 Producer:消息的起点
Producer 就是发送消息的一方。你想想看,如果 Producer 把消息发出去,但 Broker 没收到,那消息就丢了。这是最常见的丢失场景之一。
Producer 的工作流程大致是这样的:
- 序列化:把对象转成字节数组。
- 分区选择:决定这条消息去哪个 Partition。
- 发送:把数据发往 Broker。
我的经验: 我曾经遇到过一个线上问题,Producer 端设置了 acks=0,结果 Broker 挂了,消息直接丢了,Producer 还一脸无辜地返回成功。所以,我个人习惯生产环境至少用 acks=1,核心数据用 acks=all。
2.3 Broker:消息的存储与中转
Broker 是 Kafka 的服务端节点。一个 Kafka 集群由多个 Broker 组成。每个 Broker 负责存储一部分数据,并处理 Producer 和 Consumer 的请求。
Broker 层面有两个概念特别重要:
- Topic(主题):消息的逻辑分类。比如订单消息发到
ordersTopic,日志消息发到logsTopic。 - Partition(分区):Topic 的物理分片。一个 Topic 可以分成多个 Partition,每个 Partition 是一个有序的、不可变的日志文件。
为什么要分区?说白了就是为了水平扩展。如果只有一个 Partition,那吞吐量就受限于单台机器的磁盘和网络。分区之后,多个 Broker 可以并行处理。
| 概念 | 作用 | 丢失风险点 |
|---|---|---|
| Topic | 消息的逻辑分类 | 配置错误导致数据写入错误 Topic |
| Partition | 物理分片,实现并行 | Leader 副本切换时可能丢数据 |
| Replica | 副本,保证高可用 | ISR 列表过小,未同步副本被剔除 |
避坑指南: 我曾经见过一个运维同事,把 Topic 的 min.insync.replicas 设成了 1,结果 Leader 挂了,新的 Leader 没有完整数据,消息就丢了。记住,min.insync.replicas 至少要设为 2,配合 acks=all 才能保证不丢。
2.4 Consumer:消息的终点
Consumer 从 Broker 拉取消息进行处理。Consumer 会维护一个 Offset,记录自己消费到了哪个位置。
Consumer 的丢失场景通常发生在:
- 自动提交 Offset:消息还没处理完,Offset 就提交了。这时候 Consumer 挂了,重启后从已提交的 Offset 开始消费,中间的消息就丢了。
- Rebalance 期间:分区重新分配,如果 Offset 没处理好,也可能导致重复消费或丢失。
核心原则: 先处理业务逻辑,再提交 Offset。我个人习惯把自动提交关掉,手动控制提交时机。
2.5 Offset:消息的坐标
Offset 是消息在 Partition 中的唯一编号。你可以把它想象成书签——你读到第 100 页,下次就从第 101 页开始读。
Offset 的维护方式有两种:
- 自动提交:默认每 5 秒提交一次。简单,但有丢失风险。
- 手动提交:由业务代码控制提交时机。安全,但需要开发者自己管理。
// 手动提交示例
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
// 处理业务逻辑
process(record);
// 处理完成后再提交 Offset
consumer.commitSync();
}
}
我的建议: 如果你对数据一致性要求高,用 commitSync() 而不是 commitAsync()。虽然同步提交会阻塞,但能保证 Offset 一定提交成功。异步提交快,但回调失败时你可能不知道。
2.6 消息丢失的常见环节总结
咱们把上面讲的串起来,看看消息在哪个环节可能丢:
| 环节 | 丢失原因 | 一句话解决方案 |
|---|---|---|
| Producer 发送 | acks=0 或网络超时 |
设置 acks=all + 重试机制 |
| Broker 存储 | Leader 宕机,副本未同步 | min.insync.replicas ≥ 2 |
| Consumer 消费 | 自动提交 Offset 导致未处理 | 手动提交,先处理再提交 |
嗯,这一章的内容就到这里。你只要把 Producer、Broker、Consumer、Topic、Partition、Offset 这几个概念吃透,后面排查消息丢失的时候,你就能快速定位问题出在哪个环节。说白了,Kafka 的消息丢失,90% 的情况都逃不出上面这张表。