代码位置定位
首先让我回到投递消息的那一个地方
一直对send方法点击ctrl+鼠标,直到找到方法sendDefaultImpl
我们可以看到方法
MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);
MessageQueue选择代码解析
在函数中我们可以看到,如果开启了延迟投递,则会走上面的分支
下面我们对上面的分支进行逐行的解析
if (this.sendLatencyFaultEnable) {
try {
// 首次获取时,返回一个随机数,非首次获取时,返回上一次的数字+1
int index = tpInfo.getSendWhichQueue().incrementAndGet();
// 遍历MessageQueue列表,通过对MessageQueue取余的方式,获取具体的MessageQueue,如果获取到了,就返回对应的MessageQueue,如果获取不到就循环,并将index+1
for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) {
int pos = Math.abs(index++) % tpInfo.getMessageQueueList().size();
if (pos < 0)
pos = 0;
MessageQueue mq = tpInfo.getMessageQueueList().get(pos);
if (latencyFaultTolerance.isAvailable(mq.getBrokerName()))
return mq;
}
// 如果遍历后没有选到合适的MessageQueue,则保底再取一次
final String notBestBroker = latencyFaultTolerance.pickOneAtLeast();
int writeQueueNums = tpInfo.getQueueIdByBroker(notBestBroker);
if (writeQueueNums > 0) {
final MessageQueue mq = tpInfo.selectOneMessageQueue();
if (notBestBroker != null) {
mq.setBrokerName(notBestBroker);
mq.setQueueId(tpInfo.getSendWhichQueue().incrementAndGet() % writeQueueNums);
}
return mq;
} else {
latencyFaultTolerance.remove(notBestBroker);
}
} catch (Exception e) {
log.error("Error occurred when selecting message queue", e);
}
// 如果上面有地方报错,则至少保证用最简单的方式再试一次,保证能取到MessageQueu的队列
return tpInfo.selectOneMessageQueue();
}
我再对下面的分支进行解析
public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
if (lastBrokerName == null) {
// 如果lastBrokerName为空,则首次直接随机取一个MessageQueue,非首次轮询获取一个MessageQueue
return selectOneMessageQueue();
} else {
// 如果lastBrokerName不为空,则尽量选择broker和上一次不是同一个的MessageQueue,如果找不到,则首次直接随机取一个MessageQueue,非首次轮询获取一个MessageQueue
for (int i = 0; i < this.messageQueueList.size(); i++) {
int index = this.sendWhichQueue.incrementAndGet();
int pos = Math.abs(index) % this.messageQueueList.size();
if (pos < 0)
pos = 0;
MessageQueue mq = this.messageQueueList.get(pos);
if (!mq.getBrokerName().equals(lastBrokerName)) {
return mq;
}
}
return selectOneMessageQueue();
}
}