1. Kafka 为什么会出现在业务系统中
以银行交易系统为例。用户发起转账、刷卡消费、还款或理财申购之后,交易系统通常不只需要完成交易入账,还会触发风控、反洗钱、清算、客户通知、账务核算、数据分析等下游系统。
如果交易系统直接调用所有下游系统,系统之间耦合度会很高:
text
交易系统
├──调用风控系统
├──调用反洗钱系统
├──调用清算系统
├──调用客户通知系统
├──调用账务核算系统
└──调用数据分析系统
这种设计的问题很明显:
- 下游系统如果变慢,交易主流程也可能被拖慢。
- 某个下游系统不可用,交易系统可能被迫失败或反复重试。
- 新增一个下游系统时,交易系统往往也要改代码。
- 流量突然增大时,下游系统可能被瞬时流量打穿。
引入 Kafka 后,交易系统只需要把"交易已受理""账户余额已变动""转账已完成"这样的事件写入 Kafka 中,下游系统再按照自己的节奏消费。
text
交易系统 → Kafka Topic:bank-transaction-events
├──风控系统消费
├──反洗钱系统消费
├──清算系统消费
├──客户通知系统消费
├──账务核算系统消费
└──数据分析系统消费
这样做带来的好处有:
| 含义 | 在银行交易场景中的表现 | |
|---|---|---|
| 解耦 | 生产者不直接依赖所有消费者 | 交易系统不用逐个调用反洗钱、清算、数据分析 |
| 削峰 | Kafka 暂存突发流量 | 下游按自己的处理能力慢慢消费 |
| 异步 | 写入消息后即可继续主流程 | 交易主链路不用等待所有下游处理完成 |
| 可回放 | 消息保留一段时间,可重新消费 | 对账或数据分析出错后,可以重新拉取历史交易事件 |
这里也要注意边界。Kafka 能降低上下游之间的直接依赖,但不是"所有系统故障都不影响业务"。如果交易系统自己不可用,就不会产生新的交易事件;如果 Kafka 集群不可用,生产者写入消息也会受到影响。
2. Kafka 中一条消息会经过哪些组件
Kafka 的基础数据流如下图所示:
text
Producer → Topic → Partition → Broker
↓
Consumer Group
↓
Consumer
| 概念 | 含义 | 作用 |
|---|---|---|
| Producer | 生产者 | 发送消息的一方,比如交易系统、日志采集程序 |
| Topic | 主题 | 消息的逻辑分类,比如 bank-transaction-events |
| Partition | 分区 | Topic 下的数据分片,决定并行能力和局部顺序 |
| Broker | Kafka 节点 | 真正保存数据、处理读写请求的服务器 |
| Consumer | 消费者 | 读取并处理消息的一方,比如风控系统 |
| Consumer Group | 消费者组 | 一组共同消费同一个 Topic 的消费者 |
| Offset | 位移 | 消费者组在某个 Partition 中读到的位置 |
| Replica | 副本 | Partition 的冗余拷贝,用于提高可用性 |
| Leader | 主副本 | 对外提供读写服务的 Partition 副本 |
| Follower | 从副本 | 从 Leader 同步数据,等待故障时接替 |
Producer 不会把消息直接交给 Consumer,而是写入 Topic 下的某个 Partition;Partition 存储在 Broker 上;Consumer 通过 Consumer Group 的方式读取 Partition;Offset 记录消费进度;副本机制保证 Broker 故障时数据仍有机会继续服务。
3. Topic 与 Partition
Topic 是消息的逻辑分类。比如:
text
bank-transaction-events 保存交易流水事件
account-change-events 保存账户变动事件
risk-alert-events 保存风控告警事件
但 Kafka 不会把一个 Topic 当成一个单独的大文件来处理。Topic 会被拆成多个 Partition:
text
Topic
├──Partition 0
├──Partition 1
├──Partition 2
└──Partition 3
Partition 是 Kafka 中非常关键的概念
- 数据可以拆开存储,不必全部压在一个节点上。
- 生产和消费可以并行处理,提高吞吐量。
- 每个 Partition 内部可以保证消息顺序。
这里有一个容易踩坑的点:Kafka 只保证单个 Partition 内部有序,不保证整个 Topic 全局有序。
例如:
text
Partition 0:A → B → C
Partition 1:D → E → F
Kafka 可以保证 A、B、C 在 Partition 0 内的顺序,也可以保证 D、E、F 在 Partition 1 内的顺序,但不会保证整个 Topic 中一定是 A、B、C、D、E、F 这种全局顺序。
4. Consumer Group:同组分工,不同组独立
假设 bank-transaction-events 有 4 个 Partition,一个消费者组中有 2 个消费者:
text
Consumer Group:risk-control-group
Partition 0 → Consumer A
Partition 1 → Consumer A
Partition 2 → Consumer B
Partition 3 → Consumer B
这表示风控系统的两个消费者实例一起处理这 4 个 Partition
如果同一个 Topic 又被反洗钱系统消费,反洗钱系统可以使用另一个消费者组:
text
Consumer Group:aml-group
Partition 0 → Consumer C
Partition 1 → Consumer C
Partition 2 → Consumer D
Partition 3 → Consumer D
这样,风控系统和反洗钱系统都能读到交易消息。它们的消费进度互不影响。
因此,可以得到两个结论:
| 场景 | 是否会重复消费同一条消息 | 说明 |
|---|---|---|
| 同一个消费者组内的多个消费者 | 不会重复消费同一个 Partition 的同一条消息 | 组内是分工关系 |
| 不同消费者组 | 可以各自消费同一条消息 | 组间是独立关系 |
一个消费者组的有效消费并行度,可以先用这个公式理解:
text
有效并行度 = min(Partition 数量, Consumer 数量)
也就是说,如果 Topic 只有 3 个 Partition,即使同一个消费者组里启动 5 个 Consumer,最多也只有 3 个 Consumer 真正工作,剩下 2 个会空闲。
5. Offset
Offset 是 Partition 内部每条消息的位置编号。
text
Partition 0
Offset 0:交易 A
Offset 1:交易 B
Offset 2:交易 C
Offset 3:交易 D
Offset 有几个关键点:
- Offset 只在当前 Partition 内有意义。
- 不同 Partition 可以都有
Offset 0。 - Offset 不是消息的全局唯一 ID。
- Consumer Group 通过 Offset 记录自己消费到了哪里。
例如,风控系统消费到 Partition 0 的 Offset 10,反洗钱系统可能只消费到 Offset 3。这两个进度是独立的,因为它们属于不同的消费者组。
text
Partition 0
risk-control-group 当前 Offset:10
aml-group 当前 Offset:3
消费消息并不会让消息立刻从 Kafka 中删除。Kafka 的消息是否保留,主要由 Topic 的保留策略决定,比如保留 7 天或保留到一定大小。Offset 只是记录"某个消费者组读到了哪里"。
这也是 Kafka 能支持历史数据回放的原因:只要消息还在,就可以调整 Offset,让消费者从更早的位置重新读取。
6. Broker
Broker 是 Kafka 集群中的服务节点,可以粗略理解成一台运行 Kafka 的服务器。
一个 Kafka 集群通常由多个 Broker 组成:
text
Kafka Cluster
├──Broker 1
├──Broker 2
└──Broker 3
Topic 的 Partition 会分布在不同 Broker 上:
text
Topic:bank-transaction-events,4 个 Partition
Broker 1:Partition 0
Broker 2:Partition 1
Broker 3:Partition 2
Broker 1:Partition 3
这种分布式存储带来并行能力,也带来一个问题:如果某个 Broker 宕机,而 Partition 只有一份数据,那么这个 Partition 就无法继续提供服务。
Kafka 通过副本机制解决这个问题。
7. 副本
一个 Partition 可以有多个副本。副本数量由副本因子决定。
比如:
text
Partition 数量:4
副本因子:2
表示每个 Partition 有 2 份副本。总副本数为:
text
总副本数 = Partition 数量 × 副本因子
总副本数 = 4 × 2 = 8
但这 8 份副本不是 8 个 Follower。每个 Partition 都有一个 Leader,剩下的才是 Follower。
text
Leader 数量 = Partition 数量 = 4
Follower 数量 = 总副本数 - Leader 数量 = 8 - 4 = 4
示例:
text
Partition 0:Leader + Follower
Partition 1:Leader + Follower
Partition 2:Leader + Follower
Partition 3:Leader + Follower
Producer 和 Consumer 通常与 Leader 交互。Follower 从 Leader 同步数据。当某个 Leader 所在 Broker 宕机时,如果 Follower 数据同步得比较新,就可以接替 Leader 工作。
这里第一周只需要先理解一个大方向:Follower 的价值不是提高消费并行度,而是在 Leader 出问题时接替它,保证系统可用性。
副本因子也不能随便设置。一个 Partition 的多个副本需要放在不同 Broker 上才有意义,所以副本因子不能超过 Broker 数量。比如集群只有 3 个 Broker,副本因子就不能设置为 4。
8. Partition 和副本的区别
最容易混淆的是:副本数量增加,不代表同一个消费者组的消费并行度增加。
例如:
text
Topic 有 4 个 Partition
副本因子为 2
总副本数为 8
虽然总副本数是 8,但一个消费者组的最大有效消费并行度仍然是 4,因为消费并行度主要看 Partition 数量。