RocketMQ源码解析


JAVA后端开发知识总结(持续更新…)


RocketMQ源码解析


文章目录

  • RocketMQ源码解析
  • 一、原理
    • 1.1 Producer的启动流程
    • 1.2 Producer的顺序消息发送
    • 1.3 Producer的顺序消息消费
  • 持续补充。。。
  • 参考文档


一、原理

1.1 Producer的启动流程

RocketMQ源码解析_第1张图片

1.2 Producer的顺序消息发送

  Producer:将需要保证顺序的消息按某个属性来自定义选择 MessageQueue,相同属性的分到同一个MessageQueue,然后采取同步发送的方式发送,这时也能保证前一个消息发送成功并返回响应后,才能发送下一个。

  broker:因为Producer采用同步发送的方式,broker 会先接收到消息1,然后将消息1追加写到commitLog中,然后记录下这个消息在queue里面的offset,这个offset是有顺序的,然后刷盘操作,最后返回消息1的响应,然后Producer才能发送消息2。

  • send()
public SendResult send(Message msg, MessageQueueSelector selector, Object arg) throws MQClientException, RemotingException,
            MQBrokerException, InterruptedException {
            
        return metaProducerImpl.send(EnvPlugin.wrapperMsg(msg), selector, arg);
}

...

// 一路调用到 DefaultMQProducerImpl 的 send()
public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        
        // SYNC 表明 producer 是同步发送消息的,会等待 broker 的响应
        return this.sendSelectImpl(msg, selector, arg, CommunicationMode.SYNC, null, timeout);
}
  • sendSelectImpl()

send()的最后一个参数,会作为参数被传给select方法中的arg。

RocketMQ源码解析_第2张图片

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);
		// 获取 Topic 信息
        TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
        // messageQueueList 不为空
        if (topicPublishInfo != null && topicPublishInfo.ok()) {
            MessageQueue mq = null;
            try {
            	// 获取当前 topic 的内部队列
                List<MessageQueue> messageQueueList =
                    mQClientFactory.getMQAdminImpl().parsePublishMessageQueues(topicPublishInfo.getMessageQueueList());
                // 克隆消息
                Message userMessage = MessageAccessor.cloneMessage(msg);
                String userTopic = NamespaceUtil.withoutNamespace(userMessage.getTopic(), mQClientFactory.getClientConfig().getNamespace());
                userMessage.setTopic(userTopic);
                
				// 调用自定义的 select() 方法,传入 send() 的第三个参数(例如:orderId)作为选择队列的关键字
                mq = mQClientFactory.getClientConfig().queueWithNamespace(selector.select(messageQueueList, userMessage, arg));

            } catch (Throwable e) {
                throw new MQClientException("select message queue throwed exception.", e);
            }

			// 发送请求的逻辑部分,与发送普通消息是一样的
            if (mq != null) {
                return this.sendKernelImpl(msg, mq, communicationMode, sendCallback, null, timeout);
            } else {
                throw new MQClientException("select message queue return null.", null);
            }
        }

        throw new MQClientException("No route info for this topic, " + msg.getTopic(), null);
}

1.3 Producer的顺序消息消费

  Consumer:一个MessageQueue对应生成一个processQueue,然后向broker从特定offset拿一批消息过来,取过来时消息也是顺序排列的。然后Consumer会将这批消息放到 processQueue中的TreeMap(有序结构)中,调用自定义实现的MessageListenerOrderly的类对象进行单线程消费

顺序消费消息情况

  • SUCCESS :消费成功但不提交。
  • ROLLBACK :消费失败,消息回滚。
  • COMMIT :消费成功并且提交。
  • SUSPEND_CURRENT_QUEUE_A_MOMENT :消费失败,挂起消费队列一会儿,稍后继续消费。
  • 考虑到 ROLLBACK 、COMMIT 暂时只使用在 MySQL binlog 场景,官方将这两状态标记为 @Deprecated,相应的实现逻辑依然保留。

持续补充。。。

参考文档

《RocketMQ学习(四)——RocketMQ消息发送》

《RocketMQ学习(八)——RocketMQ顺序消息》

《RocketMQ源码目录篇》

你可能感兴趣的:(消息队列,队列,java)