【源码解析7】消息投递时选择哪一个MessageQueue源码解析

38 阅读1分钟

代码位置定位

首先让我回到投递消息的那一个地方

image.png

一直对send方法点击ctrl+鼠标,直到找到方法sendDefaultImpl
我们可以看到方法
MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);

image.png

MessageQueue选择代码解析

在函数中我们可以看到,如果开启了延迟投递,则会走上面的分支
image.png

下面我们对上面的分支进行逐行的解析

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();
	}
}