「日拱一卒」带你探索RocketMQ消息发送(六)

112 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

前言

上篇文章,我们主要跟大家一起了解了查找 Topic 路由信息的细节,简单来说,就是发送消息前,需要根据消息的 Topic 查询它的路由信息,这样 Producer 才知道该把消息发往哪个 Broker。今天,我们继续来看 RocketMQ 消息发送的后续逻辑吧~

消息应该发往哪个队列?

当 RocketMQ 获取到了 Topic 的路由信息后,需要根据路由信息以及 Broker 信息来选择一个队列进行发送,接下来我们一起看看 RocketMQ 是如何选择消息队列的。

选择消息队列的方法主要在 DefaultMQProducerImpl#selectOneMessageQueue 中,入参为 Topic 路由信息和 lastBrokerName (第一次为 null):

image.png

继续查看具体的实现,可以看到 MQFaultStrategy#selectOneMessageQueue 有两个不同的选择队列分支:

image.png

  • 如果 sendLatencyFaultEnable = false,即默认不启用 Broker 故障延迟机制时,会调用 TopicPublishInfo#selectOneMessageQueue 进行选择。

    • 如果 lastBrokerName = null ,即第一次执行消息队列选择时,则会取 sendWhichQueue 当前的值(线程安全,用 volatile 修饰的 ThreadLocal 变量,每选择一次队列时都会自增 1),将 sendWhichQueue 与 TopicPublishInfo 中的 MessageQueueList 长度取模得到 index,然后取 MessageQueueList 中 index 位置的队列出来作为本次消息发送的队列。

    image.png

    image.png

    • 如果 lastBrokerName 不为null,那么这个 lastBrokerName 表示上一次选择的执行发送消息失败的 Broker,那就需要规避掉这个 Broker,规避的方式其实就是有一个for循环,依次判断计算后 index 对应选择出来的队列,它的 BrokerName 与 lastBrokerName 是否相同,如果不同,则选择出来;相同则继续遍历下一个队列。

    image.png

  • 如果 sendLatencyFaultEnable = true,则启用 Broker 故障延迟机制时,则会走以下这部分逻辑:

    • 首先先轮询获取一个消息队列
    • 验证该消息队列是否可用:latencyFaultTolerance.isAvailbale 方法主要做这个事情,细节限于篇幅就不展开了~
    • 如果返回的 MesageQueue 可用,则移除 latencyFaultTolerance 关于该 Topic 的条目,表明该Broker已恢复

    image.png

小结

本文主要跟大家一起学习了 RocketMQ 选择消息发送队列的机制,主要分两种情况:

  • 关闭 Broker 故障规避机制,选择队列的方式是采用轮询
  • 开启 Broker 故障规避机制,首先轮询队列,队列如果是可用的,则返回;如果是不可用的,则尝试从规避列表中选一个队列,如果选中了则返回

下一篇文章,将继续探索 RocketMQ 的发送机制,大家多多支持~