8.consumer

  1. 消息的消费者,从消息获取方式分为:
    1. 拉 - 推包含了拉,所以拉不再单独说明
  2. 推 com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer
    1. 从使用上来看,数据是broker端源源不断的将消息推到消费者
    2. 从消息的消费方式上,分为:
      1. 集群消费:所有的消费者平均消费一份消息
      2. 广播消费:每个消费者各自消费同一份消息 
    3. 从消费的顺序上,又可分为:
      1. 并发消费
      2. 顺序消费
  3. 集群并发推方式的消费实现:
    1. 首先需要介绍一下rebalance,何谓rebalance?
      rebalance即重新平衡的意思,它是实现集群消费的关键
      如何进行rebalance呢?参见下图:

      前提1: consumer会每30s从nameserver上更新所订阅的topic路由列表,同时会更新broker路由->brokerName与角色和地址关系
      前提2: consumer会每30s与所有broker进行一次心跳,将clientid,topic,group发送至broker
      rebalance开始: consumer会每10s进行一次rebalance
      1 首先选择一个broker,根据topic和group查询到订阅此topic的属于同一group的所有的consumer clientid
      2 根据rebalance策略,进行分配.rebalance完毕之后,就可以知道当前的consumer消费哪些broker的哪些queue
      3 这个对应关系呢,对应着一个重要的对象,如下图,对于上面rebalance之后的结果会产生8个PullRequest对象,分别对应8个队列:

    2. 接着来看消息拉取的流程:

      1. PullMessageService为一个阻塞队列服务,其内有一个线程不断轮询队列,获取PullRequest对象,调用DefaultMQPushConsumerImpl进行消息拉取
      2. DefaultMQPushConsumerImpl消息拉取前进行状态,参数校验和准备,并负责构造回调实例PullCallback进行消息的消费. 调用PullAPIWrapper进行消息拉取
      3. PullAPIWrapper主要负责broker路由的解析,压力均衡
      4. NettyRemotingClient为netty封装,负责与broker通信,并在结果返回后回调PullCallback
      5. PullCallback对返回的结果进行解码,更新下次拉取的偏移量,并调用ConsumeMessageService触发客户端消费,它还会将PullRequest放回PullMessageService,从而形成一个循环.
      6. ConsumeMessageService负责调用客户端的并发消费或顺序消费,并处理消费的结果.
        1. 对于广播模式,消费失败的消息不作处理
        2. 对于集群模式,消费失败的发到重试队列,发送失败的尝试让客户端继续消费
        3. 对于集群模式,消费失败的消息且重试次数>16,则发往DLQ,表示该消息不再重试,为死消息.

    3. 3.a rebalance流程中,产生的PullRequest对象,其中的属性为netxOffset,之后拉取消息都会以此偏移量为标准拉取,那么它从那里来的?

      /**
       * Consumer从哪里开始消费<br>
       * 
       * @author shijia.wxr<vintage.wang@gmail.com>
       */
      public enum ConsumeFromWhere {
          /**
           * 一个新的订阅组第一次启动从队列的最后位置开始消费<br>
           * 后续再启动接着上次消费的进度开始消费
           */
          CONSUME_FROM_LAST_OFFSET,
          /**
           * 一个新的订阅组第一次启动从队列的最前位置开始消费<br>
           * 后续再启动接着上次消费的进度开始消费
           */
          CONSUME_FROM_FIRST_OFFSET,
          /**
           * 一个新的订阅组第一次启动从指定时间点开始消费<br>
           * 后续再启动接着上次消费的进度开始消费<br>
           * 时间点设置参见DefaultMQPushConsumer.consumeTimestamp参数
           */
          CONSUME_FROM_TIMESTAMP,
      }

      rebalance中,如果topic路由发生变化,会新生成PullRequest,其中的属性netxOffset采用用户设置的ConsumeFromWhere,计算响应的偏移量.

      1. 首先说下集群消费模式下的offset请求:


      2. 针对返回的offset>=0的情况,三种消费位置都直接接受,即从offset处消费

      3. 只有对于offset<0的情况(即这个topic的queue没有被此group消费过,或者说这个group第一次启动)不一样:
        1. CONSUME_FROM_LAST_OFFSET: 会继续拉取队列的最大偏移量作为消费的起始位置
        2. CONSUME_FROM_FIRST_OFFSET: 消费的起始位置为0
        3. CONSUME_FROM_TIMESTAMP: 首先根据时间戳定位到consumerqueue的位置文件上,通过二分查找法遍历commitlog中的消息的时间戳,查找起始位置
      4. 广播模式与集群模式类似,唯一不同的是不会从broker查询,而是从本地文件查询offset


    4. 消息拉取流程中的偏移量:
      1. 由上面的消息拉取流程(DefaultMQPushConsumerImpl)可知,拉取前有两个偏移量: 
        1. PullRequest.nextOffset 表示下次拉取的偏移量
        2. commitOffset (OffsetStore.offset)          表示当前已经消费的偏移量
      2. 通过一个具体的流程来看下这两个偏移量的具体含义,第一次消息拉取后,netxOffset变成了2:

      3. 第二次消息拉取后,netxOffset变成了4,假设消费者消费的比较慢,所以commitOffset在第二次中仍是0:

      4. 假设第三次拉取时,客户端消费了第一次拉取的消息那么commitOffset=2,故broker会存储客户端的消费偏移量:

      5. 此时可以知道,rebalance时,从broker拉取的offset就是commitOffset.
      6. 另外,客户端还会每隔5秒,将offset全量同步至broker一次.
      7. 如果broker为master,默认每次拉取消息时发送存储commitOffset的标志,如果为slave,则不发送该标志.
    5. 高可用
      1. 自身高可用
        1. 假如只有一个consumer,挂了,那么再起来后会从broker上拉取最后一次同步的offset继续消费
        2. 假如两个consumer,那么两个consumer会均分queue来消费,如果其中一个挂了,另外一个会消费挂了的consumer对应的queue,offset同样会接着挂了conumser的最后一次同步的offset继续消费. 假如挂了queue再起来,同样会均分queue, offset会取最后一次同步的offset来消费.
        3. 可能存在重复消费,需要消费端自己做幂等处理.
      2. nameserver挂了的影响
        1. 由于consumer会从nameserver列表中顺序选一个进行连接,并定时查询topic的路由信息,如果正在连接的nameserver挂了,会选择下一个nameserver进行连接
          所以nameserver挂了并不会影响consumer
      3. master挂了的影响
        1. consumer拉取消息异常
        2. 心跳异常
        3. rebalance异常(根据topic和group从某一个broker查询所有的consumer id)
        4. offset更新任务异常
        5. 但是topic路由的定时任务(从nameserver更新)最终将master地址移除:
          1. consumer解析新的关系,从slave拉数据,offset为客户端异常时的offset
          2. 以上异常消失
        6. 此时如果master起来
          1. topic路由的定时任务(从nameserver更新)最终将master地址获取
          2. consumer解析新的关系,从master拉数据,,offset为客户端最后消费的offset
      4. slave挂了的影响
        1. 只要master不挂,基本没有影响
  4. 集群顺序推方式的消费实现:
    1. 此种方式跟 集群并发推方式 区别在于一种是无序消息,一种是顺序消息.
    2. 顺序消息的消费:
      1. com.alibaba.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService

        1. 对于顺序消费,ConsumeMessageOrderlyService会定时远程锁定它所拥有的MessgeQueue,即 保证同一时刻, group<->topic<->queueid<->client是唯一的
        2. 在消息被拉取到本地后(参见上面的 消息拉取的流程的ConsumerMessgeService部分), 锁定本地的ProcessQueue, 由于ProcessQueue内部为TreeMap,故可以保证消息的顺序.
        3. 锁定后其余消费及offset更新等与并发消费一致



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值