前言
接上文
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(只规避一次),而故障延迟机制会在接下来一段时间内都对其进行规避。