【RocketMQ】MQ消息发送

🚀 优质资源分享 🚀

学习路线指引(点击解锁) 知识定位 人群定位
🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

消息发送

首先来看一个RcoketMQ发送消息的例子:

@Service
public class MQService {

    @Autowired
    DefaultMQProducer defaultMQProducer;

    public void sendMsg() {
        String msg = "我是一条消息";
        // 创建消息,指定TOPIC、TAG和消息内容
        Message sendMsg = new Message("TestTopic", "TestTag", msg.getBytes());
        SendResult sendResult = null;
        try {
            // 同步发送消息
            sendResult = defaultMQProducer.send(sendMsg);
            System.out.println("消息发送响应:" + sendResult.toString());
        } catch (MQClientException e) {
            e.printStackTrace();
        } catch (RemotingException e) {
            e.printStackTrace();
        } catch (MQBrokerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

RocketMQ是通过DefaultMQProducer进行消息发送的,它实现了MQProducer接口,MQProducer接口中定义了消息发送的方法,方法主要分为三大类:

  1. 同步进行消息发送,向Broker发送消息之后等待响应结果
  2. 异步进行消息发送,向Broker发送消息之后立刻返回,当消息发送完毕之后触发回调函数
  3. sendOneway单向发送,也是异步消息发送,向Broker发送消息之后立刻返回,但是没有回调函数
public interface MQProducer extends MQAdmin {

    // 同步发送消息
    SendResult send(final Message msg) throws MQClientException, RemotingException, MQBrokerException,
        InterruptedException;
        
    // 异步发送消息,SendCallback为回调函数
    void send(final Message msg, final SendCallback sendCallback) throws MQClientException,
        RemotingException, InterruptedException;
    
    // 异步发送消息,没有回调函数
    void sendOneway(final Message msg) throws MQClientException, RemotingException,
        InterruptedException;
    
    // 省略其他方法
}

接下来以将以同步消息发送为例来分析消息发送的流程。

DefaultMQProducer里面有一个DefaultMQProducerImpl类型的成员变量defaultMQProducerImpl,从默认的无参构造函数中可以看出在构造函数中对defaultMQProducerImpl进行了实例化,在send方法中就是调用defaultMQProducerImpl的方法进行消息发送的:

public class DefaultMQProducer extends ClientConfig implements MQProducer {

    /**
 * 默认消息生产者实现类
 */
    protected final transient DefaultMQProducerImpl defaultMQProducerImpl;
    
    /**
 * 默认的构造函数
 */
    public DefaultMQProducer() {
        this(null, MixAll.DEFAULT_PRODUCER_GROUP, null);
    }
    /**
 * 构造函数
 */
    public DefaultMQProducer(final String namespace, final String producerGroup, RPCHook rpcHook) {
        this.namespace = namespace;
        this.producerGroup = producerGroup;
        // 实例化
        defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
    }
  
    /**
 * 同步发送消息
 */
    @Override
    public SendResult send(
 Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 设置主题
        msg.setTopic(withNamespace(msg.getTopic()));
        // 发送消息
        return this.defaultMQProducerImpl.send(msg);
    }
}

DefaultMQProducerImpl中消息的发送在sendDefaultImpl方法中实现,处理逻辑如下:

  1. 根据设置的主题查找对应的路由信息TopicPublishInfo
  2. 获取失败重试次数,在消息发送失败时进行重试
  3. 获取上一次选择的消息队列所在的Broker,如果上次选择的Broker为空则为NULL,然后调用selectOneMessageQueue方法选择一个消息队列,并记录本次选择的消息队列,在下一次发送消息时选择队列时使用
  4. 计算选择消息队列的耗时,如果大于超时时间,终止本次发送
  5. 调用sendKernelImpl方法进行消息发送
  6. 调用updateFaultItem记录向Broker发送消息的耗时,在开启故障延迟处理机制时使用
public class DefaultMQProducerImpl implements MQProducerInner {
    /**
 * DEFAULT SYNC -------------------------------------------------------
 */
    public SendResult send(
 Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 发送消息
        return send(msg, this.defaultMQProducer.getSendMsgTimeout());
    }
    
    public SendResult send(Message msg,
 long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 发送消息
        return this.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout);
    }
    
    /**
 * 发送消息
 * @param msg 发送的消息
 * @param communicationMode
 * @param sendCallback 回调函数
 * @param timeout 超时时间
 */
    private SendResult sendDefaultImpl(
 Message msg,
 final CommunicationMode communicationMode,
 final SendCallback sendCallback,
 final long timeout
 ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        this.makeSureStateOK();
        Validators.checkMessage(msg, this.defaultMQProducer);
        final long invokeID = random.nextLong();
        // 开始时间
        long beginTimestampFirst = System.currentTimeMillis();
        long beginTimestampPrev = beginTimestampFirst;
        long endTimestamp = beginTimestampFirst;
        // 查找主题路由信息
        TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
        if (topicPublishInfo != null && topicPublishInfo.ok()) {
            boolean callTimeout = false;
            // 消息队列
            MessageQueue mq = null;
            Exception exception = null;
            SendResult sendResult = null;
            // 获取失败重试次数
            int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
            int times = 0;
            String[] brokersSent = new String[timesTotal];
            for (; times < timesTotal; times++) {
                // 获取BrokerName
                String lastBrokerName = null == mq ? null : mq.getBrokerName();
                // 根据BrokerName选择一个消息队列
                MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);
                if (mqSelected != null) {
                    // 记录本次选择的消息队列
                    mq = mqSelected;
                    brokersSent[times] = mq.getBrokerName();
                    try {
                        // 记录时间
                        beginTimestampPrev = System.currentTimeMillis();
                        if (times > 0) {
                            //Reset topic with namespace during resend.
                            msg.setTopic(this.defaultMQProducer.withNamespace(msg.getTopic()));
                        }
                        // 计算选择消息队列的耗时时间
                        long costTime = beginTimestampPrev - beginTimestampFirst;
                        // 如果已经超时,终止发送
                        if (timeout < costTime) {
                            callTimeout = true;
                            break;
                        }
                        // 发送消息
                        sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
                        // 结束时间
                        endTimestamp = System.currentTimeMillis();
                        // 记录向Broker发送消息的请求耗时,消息发送结束时间 - 开始时间
                        this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
                        switch (communicationMode) {
                            case ASYNC:
                                return null;
                            case ONEWAY:
                                return null;
                            case SYNC:
                                // 如果发送失败
                                if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
                                    // 是否重试
                                    if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) {
                              
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值