RocketMQ源码(十九)之消费者Rebalance

版本

  1. 基于rocketmq-all-4.3.1版本

简介

  1. 集群消息同一个消费组只能有一个消费者消费,如果一个Topic有4个MessageQueue,对于ConsumerGroupA这个消费组,如果此消费组只有一个ConsumerA,那么所有消息队列都由此消费者消费。此时ConsumerGroupA消费组增加一个ConsumerB消费者,为了提升消息的处理能力,此时多个消费者需要重新分配消费队列。这个重新分配的过程就叫做重平衡。

  2. 重平衡(Rebalance)机制主要目的

    • 提升消息的并行处理能力
    • 避免消费单点故障
  3. 触发重平衡的条件

    • 新的消费者加入消费组或者消费组成员中其中一个下线或者异常
    • 消费者拉取请求超时
    • Topic下的Queue数量变化
  4. 重平衡带来的问题

    • 消费暂停:当重平衡时,现有的Consumer会被暂停消费,等到分配完成后,才能继续消费
    • 重复消费:如果一个消费者正在消费但是并未提交偏移量,此时发生重平衡,导致另一个消费者从持久化的消费偏移量中获取的值是消费过的(但是未提交持久化),此时导致消费重复消费
    • 消费毛刺:如果重复消费的消息量比较大或者重平衡暂停的时间过长,导致积压了大量消息。可能导致重平衡之后瞬间需要消费太多积压的消息
  5. RocketMQ按照Topic维度进行Rebalance,这样会导致如果一个消费者订阅多个Topic,可能会出现分配不均的问题,处于排列前的分配更多的队列,后面的消费者处于空闲状态。由于订阅多个Topic可能导致分配不均,所以不建议在同一个消费组订阅多个Topic

  6. 触发重平衡的流程在这里插入图片描述

  7. 从上图可以看出Rebalance有多种触发机制

    • DefaultMQPushConsumerImpl启动时立即触发一次
    • 发送心跳信息,如果发生变更,Broker通知所有Consumer触发Rebalance
    • 客户端Consumer周期性触发,避免Broker通知失效
    • 客户端停止时,向Broker发送取消注册命令

Broker端

  1. Broker维护Rebalance需要的一些信息,在Rebalance过程中Broker充当协调者的角色。

  2. 在Broker内部,通过一些管理器维护与Rebalance相关的信息

    • 队列信息TopicConfigManager维护队列信息。Broker通过定时上报自己的信息给NameServer,消费者定时从NameServer拉取最新的路由信息。当队列信息发生变化,就会触发Rebalance

      // key是topic
      private final ConcurrentMap<String, TopicConfig> topicConfigTable =
          new ConcurrentHashMap<String, TopicConfig>(1024);
      
    • 消费组信息:ConsumerManager、ConsumerOffsetManager、SubscriptionGroupManager三者共同维护

      • ConsumerManager:维护了消费者组订阅信息,以及消费者组下当前的消费者实例信息,当消费者组的订阅信息或者实例发生变化,Broker都会主动给所有消费者实例发送通知,触发Rebalance
      • ConsumerOffsetManager:在Rebalance时,消费者需要从ConsumerOffsetManager查询应该从那个位置继续开始消费
      • SubscriptionGroupManager:主要是维护消费者组的一些附加信息,方便运维。

ConsumerManager

  1. ConsumerManager维护了某个消费者组的订阅信息,以及所有消费者实例的详细信息,并在发生变化时提供通知机制

    • registerConsumer:注册消费组数据。客户端通过发送RequestCode.HEART_BEAT请求给Broker,将客户端消费组相关信息注册到Broker中维护
    • unregisterConsumer:删除消费组数据。
    • 查询:发送QUERY_TOPIC_CONSUME_BY_WHOGET_CONSUME_STATS等查询消费状态
  2. 从【触发重平衡的流程】图中可以看到无论是注册还是删除消费组数据,Broker都会主动发送NOTIFY_CONSUMER_IDS_CHANGED请求来通知所有注册的Consumer实例进行Rebalance

  3. ConsumerManager#registerConsumer源码

    // 维护消费组所有的consumer实例
    private final ConcurrentMap<String/* Group */, ConsumerGroupInfo> consumerTable =
        new ConcurrentHashMap<String, ConsumerGroupInfo>(1024);
    
    public boolean registerConsumer(final String group, final ClientChannelInfo clientChannelInfo,
        ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere,
        final Set<SubscriptionData> subList, boolean isNotifyConsumerIdsChangedEnable) {
         
    
        // 查找consumer组信息,没有则创建一个
        ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group);
        if (null == consumerGroupInfo) {
         
            ConsumerGroupInfo tmp = new ConsumerGroupInfo(group, consumeType, messageModel, consumeFromWhere);
            ConsumerGroupInfo prev = this.consumerTable.putIfAbsent(group, tmp);
            consumerGroupInfo = prev != null ? prev : tmp;
        }
        // 更新Consumer信息,返回消费组下实例信息是否变化
        boolean
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值