【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)

在https://www.cnblogs.com/lccsblog/p/12249265.html中,PullMessageService负责对消息队列进行消息拉取,从远端服务器拉取消息后将消息存入ProcessQueue消息队列处理队列中,然后调用ConsumeMessageService#submitConsumeRequest方法进行消息消费,使用线程池来消费消息,确保了消息拉取于消息消费的解偶。

public interface ConsumeMessageService {
    void start();

    void shutdown();

    void updateCorePoolSize(int corePoolSize);

    void incCorePoolSize();

    void decCorePoolSize();

    int getCorePoolSize();

    ConsumeMessageDirectlyResult consumeMessageDirectly(final MessageExt msg, final String brokerName);//直接消费消息,主要用于通过管理命令收到消费消息

  //提交消息消费
void submitConsumeRequest( final List msgs, final ProcessQueue processQueue, final MessageQueue messageQueue, final boolean dispathToConsume); }
public class ConsumeMessageConcurrentlyService implements ConsumeMessageService {
    private static final InternalLogger log = ClientLogger.getLog();
    private final DefaultMQPushConsumerImpl defaultMQPushConsumerImpl;//消息推模式实现类
    private final DefaultMQPushConsumer defaultMQPushConsumer;//消费者对象
    private final MessageListenerConcurrently messageListener;//并发消息业务事件类
    private final BlockingQueue consumeRequestQueue;//消息消费任务队列
    private final ThreadPoolExecutor consumeExecutor;//消息消费线程池
    private final String consumerGroup;//消费组

    private final ScheduledExecutorService scheduledExecutorService;//添加消费任务到consumeExecutor延迟调度器
    private final ScheduledExecutorService cleanExpireMsgExecutors;//定时删除过期消息线程池

ConsumeMessageConcurrentlyService#submitConsumeRequest

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第1张图片

 

 

拉取的消息条数大于consumeMessageBatchMaxSize,则分页,ConsumeRequest的run方法封装了具体消息消费逻辑:

 

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第2张图片

 

 

检查队列是否丢弃,执行消息消费钩子函数ConsumeMessage,executeHookBefore将consumeMessageContext放到一个ArrayBlockingQueue中,有个线程在消费:

 

 

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第3张图片

 

 

看一下DefaultMQPushConsumerImpl#resetRetryAndNamespace

 

 

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第4张图片

 

恢复重试消息主题名?这是由消息重试机制决定的,mq江消息存入commitlog文件时,如果发现消息的延时级别delayTimeLevel大于0,会首先将重试主题存入在消息的属性中,然后设置主题名称为SCHEDULE_TOPIC,以便时间到后重新参与消息消费。

 

ConsumeMessageConcurrentlyService.ConsumeRequest#run

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第5张图片

 

具体的消息消费,调用应用程序消息监听器的consumeMessage方法

 

执行钩子函数

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第6张图片

 

在处理结果前再次验证一下ProcessQueue的isDroped状态值,如果设置为true,将不对结果进行处理。

ConsumeMessageConcurrentlyService#processConsumeResult:

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第7张图片

 

根据消息监听器返回的结果,计算ackIndex,如果返回CONSUME_SUCCESS,ackIndex设置为msg.szie()-1,如果返回RECONSUME_LATER,ackIndex=-1,为下文发送msgbak消息做准备。

【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录)_第8张图片

 

参考上面ackIndex的值,广播模式下,如果消费失败,则只打印日志,如果成功则不进入循环。

集群模式下,如果消费成功,不会进行sendMessageBack,如果失败,该批消息都需要发ack消息,如果消息发送ack失败,则直接将本批ack消息发送失败的消息再次封装为ConsumeRequest,然后延迟5s后重新消费。如果ack消息发送成功,该消息会“延迟消费”?。

 

从ProcessQueue中移除这批消息,返回的偏移量是移除该批消息后最小的偏移量,然后用该偏移量更新消息消费进度,以便在消费者重启后能从上一次的消费进度开始消费,避免重复消息。

当消息监听器返回RECONSUME_LATER,消息消费进度也会向前推进,这是因为当返回Reconsume_LATER,RocketMQ会创建一条原先消息属性相同的消息,拥有一个唯一的新msgId,并存储原消息ID,改消息会存入到commitlog文件中,与原先的消息没有任何关联,那该消息当然也会进入到ConsumemeQueue队列中,将拥有一个全新的队列偏移量。

 

你可能感兴趣的:(【mq读书笔记】消息消费过程(钩子 失败重试 消费偏移记录))