Kafka消费者组是什么?

一、Kafka消费者组是什么?

Consumer GroupKafka提供的可扩展且具有容错性的消费者机制。在组内多个消费者实例(Consumer Instance ),它们共享一个公共的ID即 Group ID 。组内的所有消费者协调在一起消费订阅主题(Subscribed Topics)的所有分区(Partition)。当然一个分区只能有同一个消费者组的一个Consumer 实例消费。
Consumer Group 有三个特性:

  • Consumer Group 下可以有一个或多个Consumer 实例。 这里的实例可以是一个单独的进程,也可以是同一进程下的线程;
  • Group ID 是一个字符串, 在Kafka集群中唯一标识,Consumer Group
  • Consumer Group
    下所有实例订阅主体的单个分区,只能分配给组内某个Consumer实例消费。同一个分区消息可能被多个Group 消费。

二、Kafka消费者组解决了哪些问题?

传统的消息系统中,有两种消息引擎模型:点对点模型(消息队列)、发布/订阅模型
传统的两种消息系统各有优势,我们里对比一下:

  • 传统的消息队列模型的缺陷在于消息一旦被消费,就会从队列中删除,而且只能被下游的一个Consumer消费。严格的说这不是它的缺陷,
    这是它的一个特性。但很显然这种模型的伸缩性(Scalability)很差,因为下游的多个Consumer 都要“抢”
    这个共享消息队列的消息;
  • 发布/订阅模型,允许消息被多个Consumer 消费,但它的问题也是伸缩性不高,因为订阅者都必须订阅所有主体的所有分区。

Kafka 为规避传统消息两种模型的缺点,引入了 Consumer Group 机制:

  • Consumer Group 订阅多个主题后,组内的每个实例不要求一定要订阅主题的所有分区,它只会消费部分分区中的消息;
  • Consumer Group 之间彼此队里,互不影响,它们可以订阅同一组主题而互不干涉。加上Broker端的消息留存机制,KafkaConsumer Group 完美的避开了伸缩性差的问题;
  • kafka 是用Consumer Group机制,实现了,传统两大消息引擎。如果所有实例属于同一个Group,那么它实现的就是消息队列模型;如果所有实例分别属于不同的Group,且订阅了相同的主题,那么它就实现了发布/订阅模型;

三、Consumer Group 实例数量多少才合理?

最理想的情况是Consumer实例的数量应该等于该Group订阅主题的分区总数。例如:Consumer Group 订阅了 3个主题,分别是A、B、C,它们的分区数依次是1、2、3,那么通常情况下,为该Group 设置6Consumer实例是比较理想的情形。

如果设置小于或大于6的实例可以吗?当然可以,如果你有3个实例,那么平均下来每个实例大约消费2个分区(6/3=2);如果你设置了9个实例,那么很遗憾,有3个实例(9-6=3)将不会被分配任何分区,它们永远处于空闲状态。

四、消费位移

消费者在消费的过程中要记录自己消费了多少数据,即消费位置信息,在Kafka中叫:位移(offset)。
看上去该Offset就是一个数字而已,其实对于Consumer Group 而言,它是一组KV对,Key是分区,V对应Consumer 消费该分区的最新位移。
老版本的Consumer Group把位移保存在Zookeeper中。将位移保存在Zookeeper外部系统显然好处是减少了Kafka Broker 端的状态保存开销。现在比较流行的提法是将服务器节点做成无状态的, 这样可以自由扩缩容,实现超强的伸缩性。不过在实际使用场景中,发现ZooKeeper 这类元框架并不是适合进行频繁的写更新,而Consumer Group 的位移更新却是一个非常频繁的操作。 这种大吞吐量的写操作极大的拖慢了ZooKeeper 集群的性能,在新版本的Consumer Group 中,Kafka 社区采用了将Consumer Group 位移保存在Broker 端的内部主题中。

五、Rebalance

Rebalance 本质上是一种协议,规定了一个Consumer Group 下所有Consumer 如何达成一致,来分配订阅Topic的每个分区。比如:某个Group 下有20个Consumer 实例, 它订阅了一个具有100个分区的Topic。正常情况下,Kafka 平均会为每个Consumer 分配5个分区。这个分配的过程叫Rebalance
Consumer Group触发 Rebalance有三种情况:

  • 组成员数量发生变化,比如有新的Consumer 实例加入组或离开组,抑或是有Consumer实例崩溃被“踢出”组。
  • 订阅主题数量发生变更。 Consumer Group 可以使用正则表达式订阅主题,比如
    consumer.subscribe(Pattern.complile(“t.*c”))就表明该Group订阅所有t开头,字母c结尾的主题。在Consumer Group 运行时,新创建一个满足这样条件的主题,那么会触发订阅该主题所有Group 开始Rebalance
  • 订阅主题分区数发生变化,Kakfka 一个主题,当分区数增加时,就会触发订阅该主题的所有Group开启Rebalance

Consumer Group 发生Rebalance 的过程:某个 Consumer Group 下有两个Consumer ,比如AB,当第三个成员C加入时,Kafka会触发Rebalance,并根据默认的分配策重新分配A、B、C分配分区,如下图:
http://static.cyblogs.com/kafka_rebalance.png

注意:目前Rebalance 的设计是所有Consumer实例共同参与,全部重新分配所有分区,Rebalance过程所有Consumer 实例都会停止消费,等待Rebalance 完成。Rebalance 很慢,一个Group 内有几百个Consumer实例,成功进行一次Rebalance需要好几个小时。 目前社区没有终极解决方案,最好的解决方案是规避Rebalane的发生。

参考地址

如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员微信号:chengcheng222e,他会拉你们进群。

简栈文化服务订阅号