[代码重构](master): 消费者组到底是什么?

2022年9月19日16:20:42
master
土豆兄弟 2 years ago
parent 76964434c7
commit b4be3bb5e5

@ -702,6 +702,64 @@ try {
- 主要的机制是两阶段提交2PC。引入了事务协调器的组件帮助完成分布式事务
### 2.7 消费者组到底是什么?
- 用一句话概括就是Consumer Group 是 Kafka 提供的**可扩展且具有容错性的消费者机制**。
- 既然是一个组那么组内必然可以有多个消费者或消费者实例Consumer Instance它们共享一个公共的 ID这个 ID 被称为 Group ID。组内的所有消费者协调在一起来消费订阅主题Subscribed Topics的所有分区Partition。当然每个分区只能由同一个消费者组内的一个 Consumer 实例来消费。
- Consumer Group 记住下面这三个特性
- Consumer Group 下可以有一个或多个 Consumer 实例。这里的实例可以是一个单独的进程,也可以是同一进程下的线程。在实际场景中,**使用进程更为常见一些**。
- Group ID 是一个字符串,在一个 Kafka 集群中,它标识唯一的一个 Consumer Group。
- Consumer Group 下所有实例订阅的主题的单个分区,只能分配给组内的某个 Consumer 实例消费。这个分区当然也可以被其他的 Group 消费。
- 两种消息引擎模型
- 点对点模型和发布 / 订阅模型,前者也称为消费队列。
- Kafka 的 Consumer Group 就是这样的机制。当 Consumer Group 订阅了多个主题后,**组内的每个实例不要求一定要订阅主题的所有分区,它只会消费部分分区中的消息**。
- Consumer Group 之间彼此独立,互不影响,它们能够订阅相同的一组主题而互不干涉。再加上 Broker 端的消息留存机制Kafka 的 Consumer Group 完美地规避了上面提到的伸缩性差的问题。
- 可以这么说Kafka 仅仅使用 Consumer Group 这一种机制,却同时实现了传统消息引擎系统的两大模型:
- 如果所有实例都属于同一个 Group那么它实现的就是消息队列模型如果所有实例分别属于不同的 Group那么它实现的就是发布 / 订阅模型。
- 在实际使用场景中,我怎么知道一个 Group 下该有多少个 Consumer 实例呢?
- **理想情况下Consumer 实例的数量应该等于该 Group 订阅主题的分区总数。**
- 假设一个 Consumer Group 订阅了 3 个主题,分别是 A、B、C它们的分区数依次是 1、2、3那么通常情况下为该 Group 设置 6 个 Consumer 实例是比较理想的情形,因为它能最大限度地实现高伸缩性。
- **在实际使用过程中一般不推荐设置大于总分区数的 Consumer 实例**。设置多余的实例只会浪费资源,而没有任何好处。
- 针对 Consumer GroupKafka 是怎么管理位移的呢?你还记得吧,消费者在消费的过程中需要记录自己消费了多少数据,即消费位置信息。在 Kafka 中这个位置信息有个专门的术语位移Offset
- 看上去该 Offset 就是一个数值而已,其实对于 Consumer Group 而言,它是一组 KV 对Key 是分区V 对应 Consumer 消费该分区的最新位移。
- 如果用 Java 来表示的话,你大致可以认为是这样的数据结构,即 Map<TopicPartition, Long>,其中 TopicPartition 表示一个分区,而 Long 表示位移的类型。
- Kafka 源码中并不是这样简单的数据结构,而是要比这个复杂得多
- Kafka 有新旧客户端 API 之分,那自然也就有新旧 Consumer 之分。老版本的 Consumer 也有消费者组的概念,它和我们目前讨论的 Consumer Group 在使用感上并没有太多的不同,只是**它管理位移的方式和新版本是不一样的**。
- 老版本的 Consumer Group 把位移保存在 ZooKeeper 中。Apache ZooKeeper 是一个分布式的协调服务框架Kafka 重度依赖它实现各种各样的协调管理。将位移保存在 ZooKeeper 外部系统的做法,最显而易见的好处就是减少了 Kafka Broker 端的状态保存开销。
- **现在比较流行的提法是将服务器节点做成无状态的,这样可以自由地扩缩容,实现超强的伸缩性。**
- Kafka 最开始也是基于这样的考虑,才将 Consumer Group 位移保存在独立于 Kafka 集群之外的框架中。
- 发现了一个问题,即 ZooKeeper 这类元框架其实并不适合进行频繁的写更新,而 Consumer Group 的位移更新却是一个非常频繁的操作。这种大吞吐量的写操作会极大地拖慢 ZooKeeper 集群的性能,因此 Kafka 社区渐渐有了这样的共识:将 Consumer 位移保存在 ZooKeeper 中是不合适的做法。
- 于是,在新版本的 Consumer Group 中Kafka 社区重新设计了 Consumer Group 的位移管理方式,采用了将位移保存在 Kafka 内部主题的方法。这个内部主题就是让人既爱又恨的 __consumer_offsets。
- **新版本的 Consumer Group 将位移保存在 Broker 端的内部主题中**。
- 最后,我们来说说 Consumer Group 端大名鼎鼎的重平衡,也就是所谓的 Rebalance 过程。我形容其为“大名鼎鼎”,从某种程度上来说其实也是“臭名昭著”,因为有关它的 bug 真可谓是此起彼伏,从未间断
- Rebalance 本质上是一种协议,规定了一个 Consumer Group 下的所有 Consumer 如何达成一致,来分配订阅 Topic 的每个分区。
- 比如某个 Group 下有 20 个 Consumer 实例,它订阅了一个具有 100 个分区的 Topic。正常情况下Kafka 平均会为每个 Consumer 分配 5 个分区。这个分配的过程就叫 Rebalance。
- 那么 Consumer Group 何时进行 Rebalance 呢Rebalance 的触发条件有 3 个。
- 组成员数发生变更。比如有新的 Consumer 实例加入组或者离开组,抑或是有 Consumer 实例崩溃被“踢出”组。
- 订阅主题数发生变更。Consumer Group 可以使用正则表达式的方式订阅主题,比如 consumer.subscribe(Pattern.compile(“t.*c”)) 就表明该 Group 订阅所有以字母 t 开头、字母 c 结尾的主题。在 Consumer Group 的运行过程中,你新创建了一个满足这样条件的主题,那么该 Group 就会发生 Rebalance。
- 订阅主题的分区数发生变更。Kafka 当前只能允许增加一个主题的分区数。当分区数增加时,就会触发订阅该主题的所有 Group 开启 Rebalance。
- Rebalance 发生时Group 下所有的 Consumer 实例都会协调在一起共同参与。你可能会问,每个 Consumer 实例怎么知道应该消费订阅主题的哪些分区呢?这就需要分配策略的协助了。
- 当前 Kafka 默认提供了 3 种分配策略,每种策略都有一定的优势和劣势,我们今天就不展开讨论了
- 例子来说明一下 Consumer Group 发生 Rebalance 的过程。假设目前某个 Consumer Group 下有两个 Consumer比如 A 和 B当第三个成员 C 加入时Kafka 会触发 Rebalance并根据默认的分配策略重新为 A、B 和 C 分配分区,如下图所示:
- ![Rebalance的过程](pic/Rebalance的过程.png)
- 显然Rebalance 之后的分配依然是公平的,即每个 Consumer 实例都获得了 3 个分区的消费权。这是我们希望出现的情形。
- Rebalance 过程对 Consumer Group 消费过程有极大的影响
- 在 Rebalance 过程中,所有 Consumer 实例都会停止消费,等待 Rebalance 完成。
- 其次,目前 Rebalance 的设计是所有 Consumer 实例共同参与,全部重新分配所有分区。其实更高效的做法是尽量减少分配方案的变动。
- 例如实例 A 之前负责消费分区 1、2、3那么 Rebalance 之后,如果可能的话,最好还是让实例 A 继续消费分区 1、2、3而不是被重新分配其他的分区。这样的话实例 A 连接这些分区所在 Broker 的 TCP 连接就可以继续用,不用重新创建连接其他 Broker 的 Socket 资源。
- 最后Rebalance 实在是太慢了。曾经,有个国外用户的 Group 内有几百个 Consumer 实例,成功 Rebalance 一次要几个小时!
- 最好的解决方案就是避免 Rebalance 的发生。
- 补充
- 消费组中的消费者个数如果超过topic的分区数就会有消费者消费不到数据。但如果是同一个消费组里的两个消费者通过assign方法订阅了同一个TopicPartition是不是会有一个消费者不能消费到消息
- 如果使用assign则表明该consumer是独立consumerstandalone consumer它不属于任何消费者组。独立consumer可以订阅任何分区彼此之间也没有关系即两个独立consumer可以订阅并消费相同的分区
- 减少topic的分区数可以减少服务部署时rebalance的时间呢
- 减少consumer个数也有缩短rebalance。
- Kafka 社区重新设计了 Consumer Group 的位移管理方式”
- 0.9版本引入了新版本consumer。新版本将位移保存在__consumer_offsets中不需要额外配置。如果你想保存在外部的Zk集群中那么设置consumer端参数enable.auto.commit=false然后自己调用ZooKeeper API提交位移到Zk即可。
### 2.8 揭开神秘的“位移主题”面纱

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Loading…
Cancel
Save