coordinator与offset管理和consumer rebalance

Coordinator与offset管理和Consumer Rebalance

消费者组

消费者组(consumer group)是Kafka提供的可扩展且具有容错性的消费者机制

主要有三个特性:

  • consumer group下可以有一个或多个消费者,或是消费者实例(consumer instance),consumer instance可以是一个进程,也可以是一个线程
  • group.id:是一个字符串,消费者组的唯一标识
  • 一个group内部,1个parition只能被1个consumer拥有,也可以分配给其他Group的consumer

为什么在一个group内部,1个parition只能被1个consumer拥有

在一个Group内部,是不允许多个consumer消费同一个partition,所以对于一个topic,一个group,其中partition的个数 >= consumer的个数。

例如:对于一个topic,有4个partition,那么在一个group内部,最多只能有4个consumer,当再加入新的consumer时,也不会分配到partition

  • 一个partition只能被一个group中的一个consumer消费,是为了保证1个partition消息的时序
  • 每个topic的每个partition的每个consumer group对应1个offset,即结构为键值对类型:(topic,partition,consumer_group_id)-offset,如果一个group内多个消费者消费同一个partition,那么offset就会出现问题

位移管理

参考Kafka如何保证消息不丢失不重复 中****消费端确保实现精确一次消费**

老版本中位移提交是提交到了zookeeper中,目录结构为:

/consumers/<group.id>/offsets/<topic>/<partitionId>

新版offset保存位置

提交到zookeeper有一定缺陷,它并不适合进行大批量的读写操作,尤其是写操作

Kafka提供了另一种解决方案:增加_consumer_offsets 这个topic,将offset信息写入这个topic,减少对zookeeper的依赖。其中_consumer_offsets里面记录的内容有:group.id,topic,partition,offset

每个group保存在_consumer_offsets的位置

Kafka会使用下面公式计算该group位移保存在__consumer_offsets的哪个分区上:

Math.abs(groupID.hashCode()) % numPartitions
//numPartitions 由offsets.topic.num.partitions指定,默认是50个分区

对应的分区=Math.abs(“console-consumer-46965”.hashCode()) % 50 = 11,即__consumer_offsets的分区11保存了这个consumer group的位移信息

Rebalance

什么是rebalance

rebalance本质上是一种协议,规定了一个consumer group下的所有consumer如何达成一致来分配订阅topic的每个分区。比如某个group下有20个consumer,它订阅了一个具有100个分区的topic。正常情况下,Kafka平均会为每个consumer分配5个分区。这个分配的过程就叫rebalance

什么时候发生rebalance

  • 组成员变更(新consumer加入组,已有consumer主动离开组或已有consumer崩溃)
  • 订阅主题数发生变更(使用正则表达式进行订阅,则新建topic匹配上则会发生rebalance)
  • 订阅主题的分区数发生变更

如何进行组内分区分配

  • Kafka新版本consumer默认提供两种分配策略:range和round-robin,consumer group会默认帮我们把订阅topic的分区进行分配
  • Kafka可采用可插拔式分配策略,可以创建自己的分配器实现不同的分配策略

coordinator

Kafka提供一个角色:coordinator来执行rebalance和consumer group的管理

不同版本的coordinator

  • 0.8版本的coordinator:

    • coordinator依赖zookeeper来实现管理。coordinator监听zookeeper的/consumers/《group》/ids的子节点变化以及/brokers/topics/《topic》数据变化判断是否需要进行rebalance
    • group下的每个consumer自己决定要消费哪些分区,并把自己决定抢先在zookeeper中的/consumers/《group》/owners/《topic》/《partition》下注册,需要zookeeper的协助才可以
  • 0.9版本的coordinator

    • 每个consumer group都被分配一个coordinator用于组管理和位移管理
    • 这时coordinator承担更多责任,比如:组成员管理、位移提交保护机制
    • group内成员都会和coordinator进行协商通信,对zookeeper依赖减小,性能得到提升

如何确定coordinator

在consumer group中如何确定谁是coordinator,简单分为两步:

  • 确定consumer group位移信息写入_consumers_offsets的哪个分区

    • 计算公式:partition = Math.abs(groupId.hashCode() %groupMetadataTopicPartitionCount)
    • groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定,默认是50个分区
  • 该分区Leader所在的broker就是被选定的coordinator

Rebalance Generation

consumer group 每次经过rebalance之后会变为新一届的成员,generation号都会加1,表示进入一个新版本

主要是为了保护consumer group,隔离无效的offset提交。比如:上一届的consumer成员无法提交位移到新一届的consumer group中,否则可能会报ILLEGAL_GENERATION错误

协议(protocol)

rebalance本质上是一组协议。group与coordinator共同使用它来完成group的rebalance。目前kafka提供了5个协议来处理与consumer group、 coordination相关的问题,Coordinator在rebalance的时候主要用到了前面4种请求:

  • HeartBeat请求:consumer需要定期给coordinator发送心跳表明自己还活着
  • LeaveGroup请求:主动告诉coordinator要离开consumer group
  • SyncGroup请求:group leader把分配方案告诉组内其他所有成员
  • JoinGroup请求:成员请求加入组
  • DescribeGroup请求:显示组的所有信息,包括成员信息、协议名称、分配方案、订阅信息等,通常该请求给管理员使用

liveness

consumer需要定时向coordinator发送HeartBeat请求。如果超过了设定时间没收到,coordinator就认为consumer已经挂掉了,就会开启新一轮的rebalance,并且在当前其他consumer的心跳response中添加"REBALANCE_IN_PROGRESS"

rebalance过程

在rebalance之前首先需要确定coordinator,rebalance分为两大步:

  • Join:加入组

    • 所有成员向coordinator发送JoinGroup请求,请求入组
    • coordinator收到所有成员的请求后,会从中选择一个作为Leader(注意:coordinator在收到所有成员请求之前,它会把请求放入一个叫purgatory的地方)
    • coordinator会将成员信息以及订阅信息发送给Leader
  • Sync:分配消费方案

    • Leader负责分配消费方案,即确定哪个consumer负责消费哪些topic的哪些partition
    • 分配完成,Leader将分配方案封装进SyncGroup请求中发送给coordinator,非Leader也会发SyncGroup请求,只是内容为空
    • coordinator接收到分配方案后会将方案放入SyncGroup的response中发送给各个consumer,这时组内成员就知道自己应该消费哪些分区了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-To7cCeAL-1583333635388)(images/Rebalance过程1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nkK7Thq2-1583333635391)(images/Rebalance过程2.png)]

consumer group的分区分配方案是在客户端执行的!Kafka将这个权利下放给客户端主要是因为这样做可以有更好的灵活性。Kafka默认提供了两种分配策略:range和round-robin。可以覆盖consumer的参数:partition.assignment.strategy来实现自己分配策略就好了

consumer group状态

consumer group也有状态机表明组状态的流转。coordinator会根据这个状态会对group做不同的处理

  • Dead:组内已经没有任何成员的最终状态,组的元数据已经被coordinator移除。这种状态响应各种请求都是一个response:UNKNOWN_MEMBER_ID
  • Empty:组内无成员,但位移信息还没有过期,这种状态只能响应JoinGroup请求
  • PreparingRebalance:组准备开启新的rebalance,等待成员加入
  • AwaitingSync:正在等待Leader consumer将分配方案传给各个成员
  • Stable:rebalance完成,可以开始消费了

rebalance应用场景

  • 新成员加入组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DLdxjM6r-1583333635392)(images/新成员加入组.png)]

  • 组成员崩溃

组成员崩溃和组成员主动离开是两个不同的场景。因为在崩溃时成员并不会主动地告知coordinator此事,coordinator有可能需要一个完整的session.timeout周期才能检测到这种崩溃,这必然会造成consumer的滞后。

可以说离开组是主动地发起rebalance;而崩溃则是被动地发起rebalance

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-avhNV451-1583333635394)(images/组成员崩溃.png)]

  • 组成员主动离组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iEW7DPh8-1583333635395)(images/组成员主动离组.png)]

  • 提交位移

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FxLgdtCq-1583333635397)(images/提交位移.png)]
[外链图片转存中…(img-avhNV451-1583333635394)]

  • 组成员主动离组

[外链图片转存中…(img-iEW7DPh8-1583333635395)]

  • 提交位移

[外链图片转存中…(img-FxLgdtCq-1583333635397)]

发布了5 篇原创文章 · 获赞 0 · 访问量 168

猜你喜欢

转载自blog.csdn.net/baidu_35181420/article/details/104664895