在微服务系统中,Kafka 经常和 Redis、MySQL 一起出现。
例如一个电商系统,用户支付成功之后,除了需要修改订单状态,还可能需要发送短信、更新销售统计、记录用户行为。
一种直接的实现方式是让支付服务依次调用其他服务:
text
Payment Service
|
+----> Order Service
|
+----> Notification Service
|
+----> Statistics Service
这种设计能够工作,但存在一个明显问题。
如果 Notification Service 突然响应很慢,支付服务是否要一直等待?如果统计服务暂时不可用,是否应该让支付接口失败?
这些后续操作并不一定需要在当前支付请求中同步完成。
因此,我们可以换一种方式:支付服务只负责发布"支付成功"这个业务事件,其他服务根据自己的职责处理它。
text
Payment Service
|
| PaymentSucceeded
v
Kafka
|
+----> Order Service
|
+----> Notification Service
|
+----> Statistics Service
这样,支付服务不需要依次等待三个下游服务完成各自的任务。
但是随之而来的问题是:Kafka 如何保存这些消息?三个服务怎么同时消费同一条消息?如果 Notification Service 部署了三个实例,会不会发送三次短信?
理解这些问题,就需要从 Kafka 的内部结构开始。
一、Kafka 到底是什么?
Kafka 通常被称为分布式消息系统或分布式事件流平台。
从微服务的角度,可以先把它理解成一个能够持久化保存消息,并允许不同消费者按照各自进度读取消息的系统。
例如支付服务产生一条业务事件:
json
{
"event_id": "E10001",
"event_type": "PaymentSucceeded",
"order_id": 10001,
"payment_id": "P10001"
}
这条消息表达的是:
订单 10001 对应的支付已经成功。
Payment Service 不需要直接知道有哪些服务会处理这个事件,而是把消息发布到 Kafka。
之后,订单服务可以根据消息修改订单状态,通知服务可以发送支付成功通知,统计服务可以更新销售数据。
这里体现了 Kafka 的一个重要价值:
消息生产者与消费者不需要保持直接的同步调用关系。
生产者负责发布事件,消费者根据自己的处理能力读取事件。
不过,异步并不意味着消息发布后业务就一定完成。
例如 Payment Service 把事件写入 Kafka 成功,只能说明它完成了相应的消息发布步骤,并不代表订单状态已经更新、短信已经发出。
这些操作是不同的业务阶段。
Kafka 和 RPC 的区别
上一篇已经介绍了 RPC。
RPC 通常表示:
text
Order Service
|
| ReserveInventory
v
Inventory Service
|
v
返回库存预留结果
调用方通常需要根据返回结果继续处理当前业务。
Kafka 则更适合:
text
Payment Service
|
| 发布 PaymentSucceeded
v
Kafka
|
v
其他服务后续独立处理
所以两者不是替代关系。
RPC 主要解决服务之间的远程请求与响应,Kafka 则提供异步消息存储、传递和消费能力。
什么时候使用哪一种方式,仍然取决于业务是否需要立即得到结果。
二、先认识 Producer、Broker 和 Topic
先看 Kafka 最基本的一条消息链路:
text
Producer
|
v
Kafka
|
v
Consumer
这里有三个概念。
1. Producer:消息生产者
Producer 负责把消息发送到 Kafka。
例如:
text
Payment Service
在发布支付成功事件时,就是一个 Producer。
它发送的消息可以包含:
text
Topic: payment-events
Key: 10001
Value: PaymentSucceeded 事件内容
其中:
- Topic 表示消息要写入哪个主题。
- Key 可以用于决定消息进入哪个 Partition。
- Value 是实际的消息内容。
消息还可以携带 Headers、Timestamp 等信息。
需要注意,Producer 是逻辑角色,不一定是一个独立部署的服务。Payment Service 内部的 Kafka 客户端就可以承担 Producer 的职责。
2. Broker:Kafka 服务器节点
Kafka 通常不是只运行在一台服务器上。
例如:
text
Kafka Cluster
|
+-- Broker 1
|
+-- Broker 2
|
+-- Broker 3
每个 Broker 是一个 Kafka 服务器节点,负责存储和提供相应的消息分区数据。
多个 Broker 共同组成 Kafka 集群。
但这里要避免一个误解:
Kafka 不是简单地让三个 Broker 各自保存完全不同的 Topic。
一个 Topic 可以包含多个 Partition,这些 Partition 可以分布在不同的 Broker 上,并且可以根据配置拥有副本。
关于 Broker 副本、Leader 和消息确认机制,我们会在下一篇可靠性专题中详细讨论。
3. Topic:消息的逻辑分类
Topic 可以理解成消息所属的逻辑主题。
例如:
text
payment-events
order-events
inventory-events
其中:
text
payment-events
可以保存支付相关事件。
text
order-events
可以保存订单相关事件。
生产者发布消息时,需要指定目标 Topic。
消费者则订阅自己需要处理的 Topic。
例如:
text
Payment Service
|
v
payment-events
|
+----> Order Service
|
+----> Notification Service
但这里还有一个问题。
如果 payment-events 每秒产生几十万条消息,仅仅依靠一个 Topic 名称,Kafka 怎么组织这些数据并支持多个消费者并行处理?
这就需要引出 Kafka 最重要的概念之一:Partition。
三、Partition:为什么一个 Topic 还要分成多个分区?
假设 Kafka 中有一个 Topic:
text
payment-events
我们可以把它划分为三个 Partition:
text
payment-events
|
+-- Partition 0
|
+-- Partition 1
|
+-- Partition 2
Partition 是 Kafka 存储和消费消息的重要单位。
对于一个 Partition,Kafka 会按照追加写入的方式组织消息记录。
例如:
text
Partition 0
Message A
Message B
Message C
Message D
从逻辑上看,它像一条持续追加的消息日志。
不同 Partition 可以分别保存不同消息:
text
Topic: payment-events
Partition 0:
[A] [D] [G]
Partition 1:
[B] [E] [H]
Partition 2:
[C] [F] [I]
因此,一个 Topic 不一定只有一条完整的消息序列,而可以包含多条独立的分区日志。
Kafka 为什么要设计 Partition?
主要有两个原因。
第一,让消息能够分布式存储。
一个 Topic 的不同 Partition 可以由不同 Broker 承担存储和服务请求的工作。
例如:
text
Broker 1:Partition 0
Broker 2:Partition 1
Broker 3:Partition 2
这是简化示例,实际集群还可能存在副本。
这样,一个 Topic 不需要把所有消息都集中在单个 Broker 上。
第二,提高消费并行度。
假设只有一个 Partition:
text
Partition 0
在同一个 Consumer Group 内,这个分区同一时刻通常只分配给一个 Consumer 处理。
如果有三个 Partition,就可以把它们分别交给三个 Consumer。
例如:
text
Partition 0 → Consumer A
Partition 1 → Consumer B
Partition 2 → Consumer C
三个消费者就可以并行处理不同分区中的数据。
不过,Partition 数量不是越多越好。
更多分区会增加元数据、文件、连接、复制和 Rebalance 等方面的管理成本。
分区数量应该结合吞吐量、消费并行度和业务顺序要求决定。
消息究竟进入哪个 Partition?
假设 Producer 发送三条消息:
text
order_id = 10001
order_id = 10002
order_id = 10003
如果发送消息时指定 order_id 作为 Key,生产者通常可以根据 Key 的分区规则,将相同 Key 的消息发送到同一个 Partition。
例如:
text
order_id = 10001 → Partition 1
order_id = 10002 → Partition 0
order_id = 10003 → Partition 2
后续订单 10001 的消息继续使用相同 Key,在分区数量和分区规则保持不变时,通常也会被发送到 Partition 1。
这种设计对维护同一业务对象的消息顺序非常重要。
但如果后续修改了 Topic 的分区数量,Key 到 Partition 的映射就可能发生变化,因此不能把某个 Key 永远对应某个固定分区当成绝对保证。

四、Offset:Kafka 怎么知道消息读到哪里了?
现在我们已经知道,每个 Partition 内部都保存着一条有顺序的消息日志。
但 Consumer 消费这些消息时,还需要知道自己读到哪个位置。
Kafka 使用 Offset(偏移量)标识 Partition 中的消息位置。
例如:
text
Partition 0
Offset 0 Message A
Offset 1 Message B
Offset 2 Message C
Offset 3 Message D
Offset 4 Message E
这里的 Offset 可以理解成分区日志中的位置编号。
需要特别注意:
Offset 只在对应的 Partition 内具有意义,并不是整个 Topic 统一共享的消息编号。
例如:
text
Partition 0:
Offset 0、1、2、3
Partition 1:
Offset 0、1、2、3
两个 Partition 都可以存在 Offset 0。
因此,准确定位一条 Kafka 消息,需要结合 Topic、Partition 和 Offset。
Consumer 怎么使用 Offset?
假设一个 Consumer 正在消费 Partition 0:
text
Offset 0 → 已处理
Offset 1 → 已处理
Offset 2 → 已处理
Offset 3 → 下一条待处理
它可以从 Offset 3 对应的位置继续读取。
这里我们还需要区分两个概念:
Consumer 当前读取到的位置,与它已经提交的 Offset,不一定相同。
Consumer 可以先读取多条消息,然后在处理完成后提交消费进度。
例如:
text
读取 Offset 3
|
v
处理业务
|
v
读取 Offset 4
|
v
处理业务
|
v
提交 Offset 5
在 Kafka 的常见提交语义中,提交 Offset 5 表示:
此前的相应消息已经按消费者的提交策略处理,下一次应从 Offset 5 开始读取。
这里提交的是下一条将要消费的位置。
但 Kafka 并不会因为 Consumer 提交了 Offset,就立即删除前面的消息。
这一点非常重要。
Kafka 消费完消息以后,为什么不删除?
如果把 Kafka 理解成一种简单队列,可能会认为:
text
Consumer 读取消息
|
v
消息从 Kafka 删除
但 Kafka 并不是按照这种方式管理消息生命周期。
Kafka 的消息保留主要由 Topic 的数据保留策略决定,例如保留时间、保留容量,也可以根据 Topic 的日志清理策略进行压缩整理。
这意味着:
消息是否还保存在 Kafka 中,通常与某一个 Consumer 有没有读取过它无关。
例如:
text
payment-events
Offset 0
Offset 1
Offset 2
Offset 3
订单服务已经处理到 Offset 4。
但通知服务可能才处理到 Offset 2。
Kafka 不需要因为订单服务完成消费就删除前面的消息,否则通知服务就可能无法继续读取。
这也是 Kafka 能支持多个独立 Consumer Group 消费同一个 Topic 的基础。
另外,只要所需数据还处在可读取的保留范围内,消费者就有机会通过调整消费位置重新读取历史消息。
因此,Kafka 的 Offset 不仅用于记录进度,也为失败恢复和历史消息重新处理提供了基础。
五、Consumer Group:多个消费者到底是怎么分工的?
这是 Kafka 最容易混淆、但也最重要的一个概念。
先看一个例子。
支付成功后,我们希望:
text
Order Service
更新订单状态。
同时:
text
Notification Service
发送通知。
它们都需要消费:
text
payment-events
但我们不希望它们互相抢消息。
例如订单服务消费了一条支付成功事件,不能因此让通知服务再也读不到这条消息。
Kafka 通过 Consumer Group 解决这个问题。
1. 不同 Consumer Group:各自独立消费
我们可以创建两个 Consumer Group:
text
Consumer Group A:订单处理组
Consumer Group B:通知处理组
它们都订阅 payment-events。
text
payment-events
|
+----------+----------+
| |
v v
Consumer Group A Consumer Group B
订单处理组 通知处理组
| |
v v
Order Consumer Notification Consumer
这两个 Consumer Group 拥有各自的消费进度。
例如:
text
Group A:
Partition 0 已提交 Offset 100
Group B:
Partition 0 已提交 Offset 80
这说明订单处理组的消费进度更靠前,而通知处理组还在处理较早的消息。
两个 Consumer Group 互不共享消费进度。
因此,同一条消息可以分别被不同 Consumer Group 消费。
这里需要避免一个常见误解:
Kafka 不一定是把同一条消息物理复制两份,分别发给两个 Consumer Group。
更准确的理解是:
不同 Consumer Group 根据各自的 Offset,从同一份 Topic 分区日志中读取消息。
2. 同一个 Consumer Group:分工消费
现在假设 Notification Service 的消息处理量越来越大。
原来只有一个 Consumer:
text
Notification Group
|
v
Consumer A
后来我们部署三个通知服务实例:
text
Notification Group
|
+-- Consumer A
|
+-- Consumer B
|
+-- Consumer C
这时候是不是三个 Consumer 都会收到同一条消息,然后发送三次短信?
在正常的分区分配机制下,不会。
因为它们属于同一个 Consumer Group。
Kafka 会在这个 Consumer Group 内分配 Topic 的 Partition。
假设 payment-events 有三个 Partition:
text
Notification Group
Partition 0 → Consumer A
Partition 1 → Consumer B
Partition 2 → Consumer C
这样,每个 Consumer 负责处理自己分配到的分区。
从消费任务分工角度看,三个 Consumer 可以并行处理三个 Partition 的消息。
但需要注意,这只是在正常分区分配状态下,同一个 Partition 由组内一个 Consumer 负责。发生故障、消费进度回退等情况时,同一条业务消息仍然可能被重复处理。
所以:
Consumer Group 解决的是消费任务如何分配,而不是自动保证业务操作绝不重复。
3. 为什么三个 Partition 不能让五个 Consumer 同时处理?
假设 Topic 只有:
text
Partition 0
Partition 1
Partition 2
但我们在同一个 Consumer Group 中启动了五个 Consumer:
text
Consumer A
Consumer B
Consumer C
Consumer D
Consumer E
那么典型情况下:
text
Partition 0 → Consumer A
Partition 1 → Consumer B
Partition 2 → Consumer C
Consumer D → 没有分配到分区
Consumer E → 没有分配到分区
后面两个 Consumer 暂时没有分区可消费。
这是因为,在 Kafka 常见的 Consumer Group 分区分配模型中:
一个 Partition 在同一时刻只能分配给组内一个活跃 Consumer。
所以,当 Topic 只有三个 Partition 时,同一个 Consumer Group 即使启动十个 Consumer,也不能让十个 Consumer 同时分别拥有这三个分区的消费任务。
这也是为什么 Kafka 的 Partition 数量会影响消费者组的最大分区级并行度。
4. 一个 Consumer 可以消费多个 Partition 吗?
可以。
假设:
text
Topic 有 4 个 Partition
Consumer Group 只有 2 个 Consumer
那么可能分配成:
text
Consumer A
|
+-- Partition 0
+-- Partition 1
Consumer B
|
+-- Partition 2
+-- Partition 3
一个 Consumer 完全可以负责多个 Partition。
因此,可以这样记忆:
一个 Partition 在同一组内同一时刻分配给一个 Consumer,但一个 Consumer 可以负责多个 Partition。

六、Rebalance:Consumer 挂了以后,消息由谁处理?
现在我们知道,Kafka 会把分区分配给 Consumer Group 内的消费者。
但这些 Consumer 并不会永远保持不变。
例如通知服务原本运行三个实例:
text
Notification Group
Partition 0 → Consumer A
Partition 1 → Consumer B
Partition 2 → Consumer C
假设 Consumer B 突然崩溃。
那么:
text
Partition 1
原来由谁负责?
Kafka 需要重新协调消费者组中的分区分配,让仍然存活的 Consumer 接管相应的 Partition。
例如:
text
Notification Group
Partition 0 → Consumer A
Partition 1 → Consumer A
Partition 2 → Consumer C
这个过程就涉及 Rebalance(重新平衡或分区再分配)。
哪些情况可能触发 Rebalance?
常见情况包括:
- Consumer 加入某个 Consumer Group。
- Consumer 离开消费者组。
- Consumer 崩溃或不再满足组成员存活条件。
- 订阅 Topic 的分区数量发生变化。
- 其他导致分区分配需要重新协调的情况。
例如:
text
原来:
2 个 Consumer
新增:
1 个 Consumer
合计:
3 个 Consumer
消费者组就可能重新分配 Partition,让新加入的 Consumer 承担一部分任务。
Rebalance 为什么可能带来问题?
因为消费者原来负责的 Partition 可能被转交给其他 Consumer。
假设:
text
Consumer A
读取 Offset 10
|
v
执行业务操作
|
v
还没有提交消费进度
|
v
Consumer A 崩溃
随后 Partition 被重新分配给 Consumer B。
Consumer B 从已提交的消费进度继续读取。
如果 Offset 10 对应的业务已经成功执行,但消费进度没有及时提交,那么这条消息就可能再次处理。
因此,Consumer Group 的故障恢复与 Offset 提交是联系在一起的。
这也解释了一个我们之前多次讨论的问题:
Kafka 能通过消费者组分配机制恢复消费工作,但并不能替业务保证"消息只执行一次"。
如何安全处理重复消费,需要结合业务幂等设计。
这部分会在下一篇详细讨论。
七、Kafka 能保证消息有顺序吗?
很多人在第一次接触 Kafka 时,会听到:
"Kafka 是有序的。"
但这句话必须加上一个前提:
Kafka 主要提供的是 Partition 内的消息顺序,而不是整个 Topic 的全局顺序。
例如一个 Topic 有三个 Partition:
text
Partition 0:
A → D → G
Partition 1:
B → E → H
Partition 2:
C → F → I
Partition 0 内部可以按照该分区日志中的位置顺序读取:
text
A → D → G
但不能根据三个 Partition 的日志位置,就认为整个 Topic 存在一个统一的:
text
A → B → C → D → E → F
的全局消息顺序。
不同 Partition 可以独立写入和消费,消息处理完成的先后顺序还会受到 Consumer 执行时间等因素影响。
为什么我们之前强调 order_id 作为 Key?
假设某笔订单经历:
text
OrderCreated
|
v
OrderPaid
|
v
OrderShipped
如果这三条消息分别进入不同 Partition,那么 Consumer 可能以不同速度处理各个分区。
这样就可能出现某个消费者先处理 OrderPaid,后处理 OrderCreated 的情况。
如果发送消息时统一采用:
text
Key = order_id
那么同一个订单的相关消息在分区规则保持稳定的前提下,通常会被路由到同一个 Partition。
例如:
text
Partition 1
Offset 100:OrderCreated(10001)
Offset 101:OrderPaid(10001)
Offset 102:OrderShipped(10001)
这为同一订单的按序消费提供了基础。
但需要注意:
同一个 Partition 中按顺序读取消息,不代表应用最终产生的所有业务副作用一定严格按顺序完成。
如果消费者拿到消息后又启动多个异步线程并行处理,或者把失败消息单独放入重试队列,就可能打乱业务处理完成的顺序。
因此,如果业务要求同一个订单的状态严格按顺序推进,就不仅要考虑 Kafka 的分区设计,还需要考虑消费者如何执行和提交业务操作。
Key 应该怎么选?
可以从业务对象的顺序要求出发。
例如:
text
订单事件:
Key = order_id
用户行为事件:
Key = user_id
账户变更事件:
Key = account_id
这样相同业务对象的事件更容易被组织在同一分区中。
但也不能完全忽略数据分布问题。
例如某个 Key 的消息量特别大,就可能造成单个 Partition 成为热点。
因此,Kafka 的分区键选择,实际上同时涉及:
消息顺序要求与负载分布之间的取舍。
八、Kafka 和传统任务队列有什么区别?
前面学习后台任务时,我们讲过:
text
Producer
|
v
Task Queue
|
v
Worker
Worker 取出任务,执行完成后确认。
从使用场景上看,Kafka 也能承担异步任务传递的职责。
但它的核心设计与一些传统的"取出即移除"的队列模型不同。
Kafka 更强调持久化的分区日志和消费位置。
例如:
text
Topic: payment-events
Offset 0
Offset 1
Offset 2
Offset 3
Order Consumer 可以处理到 Offset 4。
Notification Consumer 可以处理到 Offset 2。
Statistics Consumer 可以处理到 Offset 3。
这些进度互不影响。
Kafka 不需要在某个 Consumer 读取后立即删除消息。
因此,它比较适合:
- 多个系统独立消费同一类业务事件。
- 高吞吐量的异步消息处理。
- 根据保留策略保存一段时间的事件。
- 在保留范围内重新读取历史事件。
- 按 Partition 扩展消费并行度。
但这并不意味着所有异步任务都应该使用 Kafka。
如果只是一个简单的后台任务队列,任务数量不大,也不需要多个独立消费者组或历史消息重放,那么更简单的任务队列实现可能更合适。
此外,Kafka 消息并不天然具备完整的业务任务状态。
例如:
text
WAITING
RUNNING
SUCCESS
FAILED
如果需要追踪一个长任务的完整生命周期,通常还需要业务数据库或专门的任务状态管理机制。
所以 Kafka 的价值不是取代所有任务队列,而是在需要持久化事件流、消费并行和独立消费进度时提供相应能力。
九、用一个完整例子串起来
现在回到开头的支付成功事件。
假设有:
text
Payment Service
Order Service
Notification Service
Payment Service 完成支付确认后,准备发布:
text
PaymentSucceeded
消息结构:
json
{
"event_id": "E10001",
"order_id": 10001,
"status": "PAID"
}
我们把它发送到:
text
Topic = payment-events
Key = 10001
Topic 有三个 Partition。
根据 Key 分区规则,消息进入:
text
Partition 1
并被追加到某个 Offset。
text
payment-events
Partition 0:
...
Partition 1:
Offset 50 → PaymentSucceeded(10001)
Partition 2:
...
现在有两个消费者组。
text
Group A:order-group
Group B:notification-group
它们都订阅 payment-events。
Order Group
订单处理组读取这条消息:
text
PaymentSucceeded
|
v
Order Consumer
|
v
MySQL 更新订单状态
例如将订单从:
text
UNPAID
更新为:
text
PAID
然后根据消费处理策略提交 Offset。
Notification Group
通知组也能独立读取同一条消息:
text
PaymentSucceeded
|
v
Notification Consumer
|
v
发送支付成功通知
即使订单组已经完成消费,通知组也不受影响。
因为它们维护各自的消费进度。
Notification Service 扩容
假设通知处理越来越慢。
原来只有一个 Consumer:
text
notification-group
Consumer A
现在扩容到三个:
text
notification-group
Consumer A
Consumer B
Consumer C
Kafka 可以把三个 Partition 分配给三个 Consumer,实现分区级并行处理。
如果再增加两个 Consumer,而 Topic 仍然只有三个 Partition,那么通常不会进一步增加该组的分区消费并行度。
Consumer 突然崩溃
假设 Consumer B 正在处理消息时崩溃。
消费者组会重新协调分区分配。
其他 Consumer 接管相应分区,并根据已提交的 Offset 继续读取。
如果之前的业务处理已完成,但 Offset 没提交,这条消息就可能再次被处理。
因此,通知服务还需要根据 event_id 等稳定业务标识设计幂等逻辑,避免重复消费造成重复通知等副作用。
到这里,Producer、Broker、Topic、Partition、Offset 和 Consumer Group 就串成了一条完整的消息链路。

十、总结:Kafka 最重要的不是"发消息",而是消息怎么存、怎么分配、怎么继续消费
回顾这一篇,Kafka 的核心概念其实可以分成三个层次。
第一层:消息如何进入 Kafka。
Producer 将消息发送到 Topic,Kafka 根据分区规则将消息写入对应的 Partition。
Broker 负责提供消息存储与访问服务。
第二层:消息如何组织。
Topic 是逻辑主题。
Partition 是实际的分区日志。
Offset 标识一条消息在某个 Partition 中的位置。
同一个 Partition 中的消息可以按其日志位置读取,但不同 Partition 之间没有天然的全局顺序。
第三层:消息如何消费。
Consumer Group 负责组织消费者协作。
不同 Consumer Group 可以独立读取同一份 Topic 数据,并拥有各自的消费进度。
同一个 Consumer Group 内,Partition 会分配给组内 Consumer,多个 Consumer 可以分担不同 Partition 的消费工作。
把这些关系总结到一起:
| 概念 | 核心作用 |
|---|---|
| Producer | 生产并发布消息 |
| Broker | Kafka 集群中的服务器节点 |
| Topic | 消息的逻辑分类 |
| Partition | 分区存储消息,提供分区级顺序和并行度 |
| Offset | 标识分区中的消息位置 |
| Consumer | 读取并处理消息 |
| Consumer Group | 组织消费者分工,维护独立消费进度 |
| Rebalance | 组成员或分区分配变化时重新协调消费任务 |
其中最值得记住的是下面三个结论。
第一,Kafka 的消息通常不会因为被某个 Consumer 读取就立即删除。
消息的保留主要由 Topic 的数据保留和清理策略决定。
第二,同一个 Topic 可以被多个 Consumer Group 独立消费。
每个消费者组都有自己的消费位置,因此订单、通知、统计等服务可以根据各自需要处理同一类事件。
第三,一个 Partition 在同一 Consumer Group 内通常同时只分配给一个 Consumer。
因此,Partition 数量会影响消费者组的最大分区级并行度,但增加 Consumer 数量并不意味着吞吐量一定能够继续提升。
理解了这些知识之后,再学习 Kafka 的 ACK、副本复制、Offset 提交和重复消费,就不会觉得它们是互不相关的概念。
下一篇我们会进一步讨论:Kafka 为什么可能重复消费?Producer ACK 到底确认了什么?为什么 MySQL 已经更新成功,Consumer 崩溃后仍然可能再次处理同一条消息?
这些问题才是 Kafka 真正用于业务系统时,需要重点考虑的可靠性问题。