ocketMQ源码5-producer 同步发送和单向发送

RocketMQ生产者发送消息分为三种模式,分别是同步发送,异步发送和单向发送。

  • 单向发送,这个就是发送之后不用接收结果的,就是你发出去一个消息,然后就返回了,就算有结果返回也不会接收了,这是站在消息生产者的角度;

  • 同步发送的话,就是发出去一个消息,这个线程要等着它返回消息发送结果,然后你这个线程再根据这个消息发送结果再做一些业务操作等等;

  • 异步发送,这个就是在你发送消息之前要给一个callback,发送的时候,你这个线程就不用等着,该干什么就干什么,然后发送结果回来的时候,是由其他线程调用你这个callback来处理的,你可以把这个callback看作是一个回调函数,回调方法,这个方法里面的业务逻辑就是你对这个消息发送结果的处理。注意,本文介绍的消息发送只是普通的消息发送,那种事务类型的消息,我们以后会有介绍。

1. 同步发送

producer同步发送消息的示例在org.apache.rocketmq.example.simple.Producer类中,代码如下:

publicclassProducer {
    publicstaticvoidmain(String[] args)throws MQClientException, InterruptedException {
        // 1. 创建 DefaultMQProducer 对象DefaultMQProducerproducer=newDefaultMQProducer("please_rename_unique_group_name");

       
        producer.setNamesrvAddr("127.0.0.1:9876");
        /*
         * Launch the instance.
         */// todo 2. 启动 producer
        producer.start();

        for (inti=0; i < 1000; i++) {
            try {

              
                Messagemsg=newMessage("TopicTest"/* Topic */,
                    "TagA"/* Tag */,
                    ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
                );


                // 3. 发送消息SendResultsendResult= producer.send(msg);

                System.out.printf("%s%n", sendResult);
            } 
            ...
        }
        producer.shutdown();
    }
}
复制代码

我们可以看到这个代码,你是同步消息你是需要在你自己的业务线程里面接收这个sendResult的,然后在做一些业务处理,比如我这里就是打印了一下这个sendResult。

接下来我们看下它是怎样发送的,这里是调用了这个producer的send方法。

@Overridepublic SendResult send(
    Message msg)throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
    // topic 和消息长度 校验
    Validators.checkMessage(msg, this);
    msg.setTopic(withNamespace(msg.getTopic()));
    // todoreturnthis.defaultMQProducerImpl.send(msg);
}
复制代码

我们可以看到,这个 DefaultMQProducer 将这个消息给了defaultMQProducerImpl 这个实现的send方法来处理了。

public SendResult send(
    Message msg)throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
    // todo 默认超时时间3sreturn send(msg, this.defaultMQProducer.getSendMsgTimeout());
}
复制代码

defaultMQProducerImpl的send方法,加了个超时时间 ,然后有调用它的重载方法send(msg,timeout)

public SendResult send(Message msg,
    long timeout)throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
    // todo 同步模式returnthis.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout);
}
复制代码

这个send(msg,timeout)又调用了sendDefaultImpl 方法,然后他这里加了个通信模式是同步,CommunicationMode.SYNC。

1.1 DefaultMQProducerImpl#sendDefaultImpl

sendDefaultImpl 方法就比较长了了我们分成几部分来介绍:

private SendResult sendDefaultImpl(
    Message msg,
    final CommunicationMode communicationMode,
    final SendCallback sendCallback,
    finallong timeout
)throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
    // 判断状态是否是runningthis.makeSureStateOK();
    // 检查消息合法性
    Validators.checkMessage(msg, this.defaultMQProducer);
    // 随机的invokeIDfinallonginvokeID= random.nextLong();
    longbeginTimestampFirst= System.currentTimeMillis();
    longbeginTimestampPrev= beginTimestampFirst;
    longendTimestamp= beginTimestampFirst;
    // todo 获取topic信息TopicPublishInfotopicPublishInfo=this.tryToFindTopicPublishInfo(msg.getTopic());
    ...
}
复制代码

这一小段代码其实就是做了一些准备检查工作,注意第二行的个检查消息合法性,它要检查你topic,消息长度的,你不能发空消息,消息长度也不能太长,默认是不超过4m,接下来这些就是记录一下时间了,再看最后一行,就是根据你这个消息发送的topic,然后获取topic 发送消息的这么一个信息,这里面就有这topic 有几个MessageQueue,然后每个MessageQueue对应在哪个broker上面,broker 的地址又是啥的,它这个方法会先从本地的一个缓存中获取下,没有的话就从nameserv更新下这个本地缓存,再找找,要是再找不到,它就认为你没有这个topic了,然后就去nameserv上面拉取一个默认topic的一些配置信息给你用(这个其实就是在新建一个topic)。 接着这个方法往下看,接着就是判断 这个TopicPublishInfo 是否存在了,如果不存在的话就抛出异常了,没有后续了就,如果存在的话:

...
if (topicPublishInfo != null && topicPublishInfo.ok()) {
    booleancallTimeout=false;
    MessageQueuemq=null;
    Exceptionexception=null;
    SendResultsendResult=null;
    // 重试次数 区分同步、其他inttimesTotal= communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
    inttimes=0;
    // 存放发送过的broker name
    String[] brokersSent = newString[timesTotal];
    // 重试发送for (; times < timesTotal; times++) {
        StringlastBrokerName=null == mq ? null : mq.getBrokerName();
        // todo 选择message queueMessageQueuemqSelected=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()));
                }
                longcostTime= beginTimestampPrev - beginTimestampFirst;
                if (timeout < costTime) {
                    callTimeout = true;
                    break;
                }

                // todo 进行发送
                sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
                endTimestamp = System.currentTimeMillis();
                // todo isolation 参数为false(看一下异常情况)this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
                switch (communicationMode) {
                    case ASYNC:
                        returnnull;
                    case ONEWAY:
                        returnnull;
                    case SYNC:
                        if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
                            if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) {
           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值