RocketMQ发送消息之选择消息队列

本文主要介绍了RocketMQ中的消息发送策略,包括默认情况下基于上次失败broker的选择,以及开启故障延迟机制时,如何在一段时间内避开不可用的Broker。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

接上文
RocketMQ消息发送之查找Topic路由
获取到topic路由信息后,需要选择具体发送的消息队列。

选择方式

默认方式 sendLatencyFaultEnable=false

TopicPublishInfo#selectOneMessageQueue

通过传入上次发送失败的brokerName(lastBrokerName)来尽可能提高消息发送成功率。

  public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
        // 首次选择消息队列的时候,传入的lastBrokerName为null
        if (lastBrokerName == null) {
            return selectOneMessageQueue();
        } else {
            // 这里改成增强版的for循环可读性会更高一些
            // for (MessageQueue messageQueue : this. messageQueueList)
            for (int i = 0; i < this.messageQueueList.size(); i++) {
                // 序列自增后返回
                int index = this.sendWhichQueue.incrementAndGet();
                int pos = index % this.messageQueueList.size();
                MessageQueue mq = this.messageQueueList.get(pos);
                // 规避可能存在问题的broker
                if (!mq.getBrokerName().equals(lastBrokerName)) {
                    return mq;
                }
            }
            return selectOneMessageQueue();
        }
    }


 public MessageQueue selectOneMessageQueue() {
        int index = this.sendWhichQueue.incrementAndGet();
        int pos = index % this.messageQueueList.size();

        return this.messageQueueList.get(pos);
    }

Broker故障延迟机制 sendLatencyFaultEnable=true

MQFaultStrategy#selectOneMessageQueue

这里可用是指最近一段时间内发送失败的broker所包含的消息队列,可达是指成功启动的消息队列。

  public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName, final boolean resetIndex) {
        BrokerFilter brokerFilter = threadBrokerFilter.get();
        brokerFilter.setLastBrokerName(lastBrokerName);
        if (this.sendLatencyFaultEnable) {
            if (resetIndex) {
                tpInfo.resetIndex();
            }
            // 先尝试选择一个可用的消息队列
            MessageQueue mq = tpInfo.selectOneMessageQueue(availableFilter, brokerFilter);
            if (mq != null) {
                return mq;
            }
            // 没有获取可用的消息队列,则尝试选择一个可达的消息队列
            mq = tpInfo.selectOneMessageQueue(reachableFilter, brokerFilter);
            if (mq != null) {
                return mq;
            }

            return tpInfo.selectOneMessageQueue();
        }

        MessageQueue mq = tpInfo.selectOneMessageQueue(brokerFilter);
        if (mq != null) {
            return mq;
        }
        return tpInfo.selectOneMessageQueue();
    }

 /**
     * 从给定的消息队列列表中选择一个消息队列。
     * @param messageQueueList 消息队列列表
     * @param sendQueue 用于选择消息队列的索引
     * @param filter 队列过滤器
     * @return 选定的消息队列,如果没有可用的队列则返回null
     */
    private MessageQueue selectOneMessageQueue(List<MessageQueue> messageQueueList, ThreadLocalIndex sendQueue, QueueFilter ...filter) {
        // 检查消息队列列表是否为空
        if (messageQueueList == null || messageQueueList.isEmpty()) {
            return null;
        }

        if (filter != null && filter.length != 0) {
            // 遍历消息队列列表
            for (int i = 0; i < messageQueueList.size(); i++) {
                // 计算索引,使用ThreadLocalIndex来确保线程安全地增加索引值
                int index = Math.abs(sendQueue.incrementAndGet() % messageQueueList.size());
                // 获取对应索引的消息队列
                MessageQueue mq = messageQueueList.get(index);
                boolean filterResult = true;
                // 应用所有过滤器对消息队列进行过滤
                for (QueueFilter f: filter) {
                    Preconditions.checkNotNull(f);
                    filterResult &= f.filter(mq);
                }
                // 如果通过了所有过滤器,则返回该消息队列
                if (filterResult) {
                    return mq;
                }
            }
            // 如果没有通过任何过滤器,则返回null
            return null;
        }

        // 如果没有指定过滤器,直接根据索引选择消息队列
        int index = Math.abs(sendQueue.incrementAndGet() % messageQueueList.size());
        return messageQueueList.get(index);
    }

总结

其实开不开其故障延迟机制的区别在于对于Broker不可用的定义不同,默认机制只会避开上一次发送且失败的broker(只规避一次),而故障延迟机制会在接下来一段时间内都对其进行规避。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值