同一个Topic可以在多个Broker中创建,同一个Broker中的某一个Topic可以拥有多个队列。那么如何保证消息在队列中顺序呢?
AllocateMessageQueueStrategy 消费者均衡 MessageQueueSelector 生产者均衡 topicRouteData2TopicPublishInfo
在RocketMQ 中在 org.apache.rocketmq.client.producer.selector 包中,负责Producer发送负载均衡。在创建topic的时候,每一个分区每一个topic都有会topicConf信息。
在topic config中都有writeQueueNum. 在producer 从name获取topic config信息后,会把这个信息转化成MessageQueue信息。在Producer 发送信息时,会通过MessageQueueSelector 来进行负载均衡。
在RocketMQ 中消息只保证在同一个分区同一个Queue队列的顺序性。 所以,要保证业务逻辑的顺序性,可以通过MessageQueue 来完成操作。
Producer发送负载均衡逻辑代码:
//MessageQueue 队列选择器
public interface MessageQueueSelector {
/**
* 选择出发送消息的MessageQueue
* @param mqs 与该topic相关联的所有MessageQueue队列
* @param msg 发送的消息
* @param arg 业务对象
* @return 发送消息的消息队里
*/
MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg);
}
RocketMQ 提供几种负载均衡策略: 随机、散列等
public class SelectMessageQueueByRandoom implements MessageQueueSelector {
private Random random = new Random(System.currentTimeMillis());
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int value = random.nextInt();
if (value < 0) {
value = Math.abs(value);
}
value = value % mqs.size();
return mqs.get(value);
}
}
发送负载均衡源代码如下:
private SendResult sendSelectImpl(//
Message msg, //
MessageQueueSelector selector, //
Object arg, //
final CommunicationMode communicationMode, //
final SendCallback sendCallback, final long timeout//
) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
this.makeSureStateOK();
Validators.checkMessage(msg, this.defaultMQProducer);
TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic(