1. 消费者组概念:什么是消费者组、消费者组的作用、消费者组与分区的关系

1.1 什么是消费者组

消费者组,说白了就是一组消费者实例的集合。它们共享一个 group.id,协同消费一个或多个主题的数据。

我个人习惯把消费者组想象成一个「工作小组」。小组里的每个人(消费者实例)各自负责一部分任务(分区),大家互不干扰,合起来又能把整个任务做完。

举个例子:你有一个主题叫 order_events,分了 6 个分区。你起了 3 个消费者实例,都设置 group.id = "order-group"。那么 Kafka 会自动把这 6 个分区分配给 3 个消费者,每人分到 2 个。

核心定义:消费者组是 Kafka 实现点对点消费模型的基本单元。同一个组内的消费者,不会重复消费同一条消息。

1.2 消费者组的作用

消费者组解决了两个关键问题:水平扩展和故障容错。

  • 水平扩展:当消费速度跟不上生产速度时,加消费者实例就行。组内会自动重新分配分区,把负载分摊出去。
  • 故障容错:某个消费者挂了,组内其他消费者会接管它负责的分区。整个过程对业务代码透明。

我在项目中遇到过这样一个场景:双十一大促期间,订单消息量暴涨 10 倍。我们什么都没改,就加了几台消费者机器,分区自动重平衡,消费延迟立刻降下来了。这就是消费者组带来的好处。

避坑指南:我曾经以为消费者实例越多越好,结果发现分区数有限,消费者超过分区数时,多余的实例会闲置。所以消费者实例数不要超过分区总数。

1.3 消费者组与分区的关系

这是理解消费者组最核心的部分。我画了一张图,你看完就明白了。

消费者组与分区关系示意图 主题 Topic-A 分区 0 分区 1 分区 2 消费者组:order-group 消费者实例 A 消费者实例 B 消费者实例 C 负责分区 0 负责分区 1 负责分区 2 每个分区只被组内一个消费者消费,一个消费者可以消费多个分区

这张图展示了最核心的关系:

  • 一个主题的多个分区,被均匀分配给组内的消费者实例
  • 每个分区只能被组内的一个消费者消费
  • 一个消费者可以消费多个分区

注意:如果消费者实例数大于分区数,多出来的实例会一直空闲。这不是 Bug,是设计如此——Kafka 保证每个分区只被一个消费者消费,不会出现多个消费者抢同一个分区的情况。

1.4 分区分配策略

Kafka 提供了几种分区分配策略,我挑最常用的两种说一下:

策略名称 分配方式 适用场景
RangeAssignor 按主题分区,每个主题独立分配 分区数均匀,消费者订阅相同主题
RoundRobinAssignor 所有分区统一轮询分配 消费者订阅多个主题,希望负载更均衡
StickyAssignor 尽量保持已有分配不变 频繁重平衡场景,减少分区移动

我个人习惯用 StickyAssignor。为什么?因为生产环境中重平衡是常态,Sticky 策略能最大程度减少分区在消费者之间的「搬家」,降低不必要的开销。

经验之谈:我曾经在一个 200 个分区、20 个消费者的集群上,因为默认的 Range 策略导致每次重平衡都要移动大量分区。换成 Sticky 后,重平衡时间从 30 秒降到了 5 秒以内。

1.5 消费者组的生命周期

一个消费者组从创建到销毁,大致经历这几个阶段:

  1. 加入组:消费者向协调器(Coordinator)发送 JoinGroup 请求
  2. 选组长:协调器选出一个消费者作为 Group Leader
  3. 分配分区:Leader 根据分配策略,决定每个消费者负责哪些分区
  4. 同步分配:Leader 把分配结果发给协调器,协调器广播给所有消费者
  5. 开始消费:每个消费者开始拉取自己负责的分区的消息

嗯,这里要注意:如果消费者心跳超时或者主动离开,会触发重平衡(Rebalance),重新走一遍上面的流程。

一句话总结:消费者组是 Kafka 实现「水平扩展 + 故障容错」的基石。理解分区与消费者的映射关系,是掌握消费者组负载均衡的第一步。