rocketmq5--(三)--broker发送消息给消费者

202412/30回过头来记录一下:之前一直找不到在哪里把消息丢给消费者(2024/11/23),找了很久都没找到,就放弃了,然后发现,我靠原来是在poplongpollingservice里。。。。还是乱打断点,偶然找到的。。。这属于运气好,好的,接下来处理consumer流程

RocketMQ主要有两种消费模式:CLUSTERING集群消费(默认)和BROADCASTING广播消费。在CLUSTERING模式下,一个ConsumerGroup中的Consumer实例根据队列分配策略算法为Consumer分配队列,平均分摊(默认)消费消息。例如,如果Topic是Test的消息发送到该主题的不同队列中,发送了有100条消息,其中一个ConsumerGroup有3个Consumer实例,那么根据队列分配算法,每个队列都会有消费者,每个消费者实例只消费自己队列上的数据,消费完的消息不能被其他消费实例消费。在BROADCASTING模式下,消息会被所有在该Topic的ConsumerGroup中的Consumer实例共同消费。消费模式在创建Consumer时指定,不同的消费模式其内部机制也不同,消息的消费方式、记录消费进度、消息的消费状态等也都各不相同。

对于长时间没有 ACK 的消息,Broker 端并非毫无办法。Pop 消费引入了消息不可见时间(invisibleTime)的机制。当 Pop 出一条消息后,这条消息对所有消费者不可见,即进入不可见时间,当它超过该时刻还没有被 ACK,Broker 将会把它放入 Pop 专门的重试 Topic(这个过程称为 Revive),这条消息重新可以被消费。https://my.oschina.net/u/4249738/blog/5609999

rocketmq5有三种消费者:默认是pop

    CONSUME_ACTIVELY("PULL")    --
    CONSUME_PASSIVELY("PUSH")   --
    CONSUME_POP("POP")          -- 对应PopLongPollingService

顺序写随机读:

发消息时,Productor的消息确实是顺序写CommitLog
订阅消息时,Consumer也是顺序读ConsumeQueue,然而根据其中的起始物理位置偏移量offset读取消息真实内容却是随机读CommitLog。

https://zhouj000.github.io/2021/05/10/rocketmq-source1/

pullRequestHoldService

ReputMessageService

源码阅读建议:因为rocketmq中有很多topic,而同一套代码流程可能同时处理我们的生产者消费者,也可能处理系统的相关消息,比如heartbeat,所以为了打断点的时候能确保是我们的代码触发的,所以建议如下修改源码,这样一旦运行到断点处就能确定是我们的代码触发的:

 @Override
    public GetMessageResult getMessage(final String group, final String topic, final int queueId, final long offset,
        final int maxMsgNums, final int maxTotalMsgSize, final MessageFilter messageFilter) {
   
   
        if (this.shutdown) {
   
   
            LOGGER.warn("message store has shutdown, so getMessage is forbidden");
            return null;
        }
        ......
        if (topic.equals("testz")){
   
                       #testz是我们自己的代码中使用的topic
            System.out.println("i found you:testz");   #随便来两条语句,然后在这里打断点
            int a=1;                                   #这样就能确保运行到这个断点的时候topic是我们自己的topic
                                                       #而不会被heartbeat等系统消息所干扰
        }
        ......

消费逻辑:

client sdk中consumer有两种消息拉取模式:broker push和consumer pull 
20241230 补充:rocketmq5还有pop方式

三个where:

commitWhere表示消费者已经消费到哪了,也是另开一个线程去flush即在CommitRealTimeService.run中刷到磁盘
flushWehre表示数据已经刷盘到哪里了,flushWhere的数据也叫confirmedOffset
妈的,一大堆offset、where,都绕晕了

ReputService:

ReputService是DefaultMessageStore的一个内部类

ReputService.run
  while !this.isStopped:
    ReputService.doReput
      if ReputService.reputFromOffset < CommitLog.getMinOffset:  #commitLog的minOffset表示目前存在的消息的最小offset
                                                                 #因为offset是递增的,所以这就表示凡是offset小于minOffset
                                                                 #的消息都已经被删除了,也就是对应的文件expired了
        ReputService.reputFromOffset = CommitLog.getMinOffset    #所以此时需要重置reputOffset为minOffset
                                                                 #即第一条有效地commitLog
        while doNext:                                            
          ok=isCommitLogAvailable:                               #检测commitLog的offset是否有变动,
            new=ReputService.getReputEndOffset                   #首先获取commitLog的位置
                                                                 #有两个offset:maxOffset和confirmedOffset
                                                                 #maxOffset表示commitLog的当前位置
                                                                 #并且这一块数据可能还没有flush到磁盘,所以是不稳定的
                                                                 #confirmedOffset则是已经刷新到磁盘的数据的最大offset
                                                                 #所以如果开启读未提交则返回maxOffset,反之返回confirmedOffset
              MessageStoreConfig.isReadUnCommitted?CommitLog.getMaxOffset():CommitLog.getConfirmOffset()
            return cur<new                                       #一旦检测到commitLog的offset大于记录的reputOffset
                                                                 #就说明有更新即本次需要doReput而不是sleep
          CommitLog.getData(reputFromOffset)                     #从commitLog获取新增的数据
                                                                 #所有数据都是存放在commitLog,consumerQueue存的是索引没有存原始数据
          CommitLog.checkMessageAndReturnSize                     #检查消息是否ok比如检查crc对不对,以及获取消息大小        
          if reputFromOffset + size > getReputEndOffset():        #如果当前reputOffset+msgSize超过了offset
            doNext = false                                        #就表示这不是一条完整的消息即所有消息都处理完了,可以结束本次循环
            break 
          if dispatchRequest.isSuccess():                         #如果这条消息ok
            if size > 0:                                          #如果size大于0
              ReputService.doDispatch                             #分发消息,默认有4个dispatch,分别是:
                                                                  #CommitLogDispatcherCalcBitMap:
                                                                  #DefaultMessageStore.CommitLogDispatcherBuildConsumeQueue、
                                                                  #DefaultMessageStore.CommitLogDispatcherBuildIndex、
                                                                  #CommitLogDispatcherCompaction
                1: 计算consumerQueue对应的bitmapFilter         
                CommitLogDispatcherCalcBitMap.dispatch            #1:CommitLogDispatcherCalcBitMap计算consumerQueue对应的bitmapFilter  
                  ...略...                                        #估计是用来加快查找的,和indexFile类似
                                                                  #不过默认是不启用的
                2:把offset写入consumerQueue文件
                CommitLogDispatcherBuildConsumeQueue.dispatch     #2:把offset写入consumerQueue文件
                  switch (tranType):                            
                    case MessageSysFlag.TRANSACTION_NOT_TYPE:     #如果是非事务消息即普通消息
                    case MessageSysFlag.TRANSACTION_COMMIT_TYPE:  #或者是COMMIT消息即已完成的事务消息
                                                                  #即prepare或者rollback的消息我们就不需要写入consumerQueue
                      DefaultMessageStore.putMessagePositionInfo  #执行分发
                        ConsumerQueueStore.putMessagePositionInfoWrapper #ConsumerQueueStoreInterface可以有多种实现:default和rocksdb
                          ConsuemrQueueStore.findOrCreateConsumeQueue    #分发时首先查找consuemrQueue对应的文件
                                                                         #会把msg的offset写入consumerQueue对应的文件
                                                                         #consumerQueue是构建在commitLog之上的逻辑队列
                                                                         #consumerQueue中只保存msg的offset
                                                                         #读取一个消息的时候要先从consuemrQueue对应的文件中
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值