Rocket MQ系列四 - 消息发送流程

RocketMQ消息发送的全部流程和落盘原理分析 前言介绍 RocketMQ目前在国内应该是比较流行的MQ 了,目前本人也在公司的项目中进行使用和研究,借着这个机会,分析一下RocketMQ 发送一条消息到存储一条消息的过程,这样会对以后大家分析和研究RocketMQ相关的问题有一定的帮助。 技术范围 分析的总体技术范围发送到存储,本文的主要目的是主要是为了认识一条消息并分析被发出且被存储的,代码中,关于 MQ 文件系统的优化,设计等。 现在出发 来自官方源码example的一段发送代码: DefaultMQProducer producer 阅读详情

        RocketMQ客户端的消息发送通常分为以下3层:

        业务层:通常指直接调用RocketMQ Client发送API的业务代码。

        消息处理层:指RocketMQ Client获取业务发送的消息对象后,一系列的参数检查、消息发送准备、参数包装等操作。

        通信层:指RocketMQ基于Netty封装的一个RPC通信服务,RocketMQ 的各个组件之间的通信全部使用该通信层。

        总体上讲,消息发送流程首先是RocketMQ客户端接收业务层消息,然后通过DefaultMQProducerImpl发送一个RPC请求给Broker,再由Broker处理请求并保存消息。

下面以DefaultMQProducer.send(Message msg)接口讲解发送流程:

        消息发送流程具体分为3步:

        第一步:调用DefaultMQProducerImpl.send()方法发送消息。

        第二步:通过设置的发送超时时间,调用defaultMQProducerImpl.send()方法发送消息。设置的超时时间可以通过sendMsgTimeout进行变更,默认是3s。

        第三步:执行defaultMQProducerImpl.sendDefaultImpl()方法。这是一个公共发送方法。

具体代码如下:

    public SendResult send(
        Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 参数检查
        Validators.checkMessage(msg, this);
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.send(msg);
    }


    public SendResult send(
        Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 默认超时时间是3s
        // private int sendMsgTimeout = 3000;
        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);
    }


    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++) {
                String lastBrokerName = null == mq ? null : mq.getBrokerName();
                // 选择发送队列
                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();
                        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()) {
                                        continue;
                                    }
                                }

                                return sendResult;
                            default:
                                break;
                        }
                    } catch (RemotingException e) {
                        endTimestamp = System.currentTimeMillis();
                        this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                        log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
                        log.warn(msg.toString());
                        exception = e;
                        continue;
                    } catch (MQClientException e) {
                        endTimestamp = System.currentTimeMillis();
                        this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                        log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
                        log.warn(msg.toString());
                        exception = e;
                        continue;
                    } catch (MQBrokerException e) {
                        endTimestamp = System.currentTimeMillis();
                        this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                        log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
                        log.warn(msg.toString());
                        exception = e;
                        if (this.defaultMQProducer.getRetryResponseCodes().contains(e.getResponseCode())) {
                            continue;
                        } else {
                            if (sendResult != null) {
                                return sendResult;
                            }

                            throw e;
                        }
                    } catch (InterruptedException e) {
                        endTimestamp = System.currentTimeMillis();
                        this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
                        log.warn(String.format("sendKernelImpl exception, throw exception, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
                        log.warn(msg.toString());

                        log.warn("sendKernelImpl exception", e);
                        log.warn(msg.toString());
                        throw e;
                    }
                } else {
                    break;
                }
            }

            if (sendResult != null) {
                return sendResult;
            }

            String info = String.format("Send [%d] times, still failed, cost [%d]ms, Topic: %s, BrokersSent: %s",
                times,
                System.currentTimeMillis() - beginTimestampFirst,
                msg.getTopic(),
                Arrays.toString(brokersSent));

            info += FAQUrl.suggestTodo(FAQUrl.SEND_MSG_FAILED);

            MQClientException mqClientException = new MQClientException(info, exception);
            if (callTimeout) {
                throw new RemotingTooMuchRequestException("sendDefaultImpl call timeout");
            }

            if (exception instanceof MQBrokerException) {
                mqClientException.setResponseCode(((MQBrokerException) exception).getResponseCode());
            } else if (exception instanceof RemotingConnectException) {
                mqClientException.setResponseCode(ClientErrorCode.CONNECT_BROKER_EXCEPTION);
            } else if (exception instanceof RemotingTimeoutException) {
                mqClientException.setResponseCode(ClientErrorCode.ACCESS_BROKER_TIMEOUT);
            } else if (exception instanceof MQClientException) {
                mqClientException.setResponseCode(ClientErrorCode.BROKER_NOT_EXIST_EXCEPTION);
            }

            throw mqClientException;
        }

        validateNameServerSetting();

        throw new MQClientException("No route info of this topic: " + msg.getTopic() + FAQUrl.suggestTodo(FAQUrl.NO_TOPIC_ROUTE_INFO),
            null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION);
    }

        sendDefaultImpl 是发送的核心方法,执行过程分为5步:

        第一步:两个检查,生产者状态、消息及消息内容。没有运行的生产者不能发送消息。消息检查主要检查消息是否为空,消息的Topic的名字是否为空或者是否符合规范;消息体大小是否符合要求,最大值为4MB,可以通过maxMessageSize设置。

        第二步:执行 tryToFindTopicPublishInfo() 方法,获取Topic路由信息,如果不存在则发送异常提醒用户。如果本地缓存没有路由信息,就通过namesrv获取路由信息,更新到本地,再返回。

具体实现如下:

    private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) {
        TopicPublishInfo topicPublishInfo = this.topicPublishInfoTable.get(topic);
        if (null == topicPublishInfo || !topicPublishInfo.ok()) {
            this.topicPublishInfoTable.putIfAbsent(topic, new TopicPublishInfo());
            this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic);
            topicPublishInfo = this.topicPublishInfoTable.get(topic);
        }

        if (topicPublishInfo.isHaveTopicRouterInfo() || topicPublishInfo.ok()) {
            return topicPublishInfo;
        } else {
            this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic, true, this.defaultMQProducer);
            topicPublishInfo = this.topicPublishInfoTable.get(topic);
            return topicPublishInfo;
        }
    }

        第三步:计算消息发送的重试次数,同步重试和异步重试的执行方式是不同的。

        第四步:执行队列选择方法 selectOneMessageQueue(),根据队列对象中保存的上次发送消息的Broker的名字和Topic的路由,选择一个Queue将消息发送到Broker,可以通过sendLatencyFaultEnable来设置是否总是发送到延迟级别较低的Broker,默认是false。

        第五步:执行sendKernelImpl()方法,该方法是发送消息的核心方法,主要用于准备通信层的入参,将请求传递给通信层,内部实现时基于Netty的,在封装为通信层request对象RemotingCommand前,会设置RequestCode表示当前请求是发送单个消息还是批量消息。

具体实现如下:

    private SendResult sendKernelImpl(final Message msg,
        final MessageQueue mq,
        final CommunicationMode communicationMode,
        final SendCallback sendCallback,
        final TopicPublishInfo topicPublishInfo,
        final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        ......

       sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage(
                            brokerAddr,
                            mq.getBrokerName(),
                            tmpMessage,
                            requestHeader,
                            timeout - costTimeAsync,
                            communicationMode,
                            sendCallback,
                            topicPublishInfo,
                            this.mQClientFactory,
                            this.defaultMQProducer.getRetryTimesWhenSendAsyncFailed(),
                            context,
                            this);

        ......
        throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null);
    }




    public SendResult sendMessage(
        final String addr,
        final String brokerName,
        final Message msg,
        final SendMessageRequestHeader requestHeader,
        final long timeoutMillis,
        final CommunicationMode communicationMode,
        final SendCallback sendCallback,
        final TopicPublishInfo topicPublishInfo,
        final MQClientInstance instance,
        final int retryTimesWhenSendFailed,
        final SendMessageContext context,
        final DefaultMQProducerImpl producer
    ) throws RemotingException, MQBrokerException, InterruptedException {
        long beginStartTime = System.currentTimeMillis();
        RemotingCommand request = null;
        String msgType = msg.getProperty(MessageConst.PROPERTY_MESSAGE_TYPE);
        boolean isReply = msgType != null && msgType.equals(MixAll.REPLY_MESSAGE_FLAG);
        if (isReply) {
            ......
        } else {
          
            if (sendSmartMsg || msg instanceof MessageBatch) {
                SendMessageRequestHeaderV2 requestHeaderV2 = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV2(requestHeader);
                request = RemotingCommand.createRequestCommand(msg instanceof MessageBatch ? RequestCode.SEND_BATCH_MESSAGE : RequestCode.SEND_MESSAGE_V2, requestHeaderV2);
            } else {
                request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader);
            }
        }

        request.setBody(msg.getBody());

        switch (communicationMode) {
            case ONEWAY:
                ......
                return null;
            case ASYNC:
                  ......
                return null;
            case SYNC:
                long costTimeSync = System.currentTimeMillis() - beginStartTime;
                if (timeoutMillis < costTimeSync) {
                    throw new RemotingTooMuchRequestException("sendMessage call timeout");
                }
                //发送同步消息方法
                return this.sendMessageSync(addr, brokerName, msg, timeoutMillis - costTimeSync, request);
            default:
                assert false;
                break;
        }

        return null;
    }



    private SendResult sendMessageSync(
        final String addr,
        final String brokerName,
        final Message msg,
        final long timeoutMillis,
        final RemotingCommand request
    ) throws RemotingException, MQBrokerException, InterruptedException {
        RemotingCommand response = this.remotingClient.invokeSync(addr, request, timeoutMillis);
        assert response != null;
        return this.processSendResponse(brokerName, msg, response,addr);
    }



    public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
        throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
        long beginStartTime = System.currentTimeMillis();
        final Channel channel = this.getAndCreateChannel(addr);
        if (channel != null && channel.isActive()) {
            try {
                doBeforeRpcHooks(addr, request);
                long costTime = System.currentTimeMillis() - beginStartTime;
                if (timeoutMillis < costTime) {
                    throw new RemotingTimeoutException("invokeSync call timeout");
                }
                RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis - costTime);
                doAfterRpcHooks(RemotingHelper.parseChannelRemoteAddr(channel), request, response);
                return response;
            } catch (RemotingSendRequestException e) {
                ......
            } catch (RemotingTimeoutException e) {
                ......
                throw e;
            }
        } else {
            this.closeChannel(addr, channel);
            throw new RemotingConnectException(addr);
        }
    }



    // Netty本身是一个异步的网络通信框架
    public RemotingCommand invokeSyncImpl(final Channel channel, final RemotingCommand request,
        final long timeoutMillis)
        throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
        final int opaque = request.getOpaque();

        try {
            final ResponseFuture responseFuture = new ResponseFuture(channel, opaque, timeoutMillis, null, null);
            this.responseTable.put(opaque, responseFuture);
            final SocketAddress addr = channel.remoteAddress();
            channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture f) throws Exception {
                    if (f.isSuccess()) {
                        // 只要返回成功,就会在回调方法operationComplete() 执行前释放锁
                        responseFuture.setSendRequestOK(true);
                        return;
                    } else {
                        responseFuture.setSendRequestOK(false);
                    }

                    responseTable.remove(opaque);
                    responseFuture.setCause(f.cause());
                    // 释放锁
                    /*
                     *
                        public void putResponse(final RemotingCommand responseCommand) {
                            this.responseCommand = responseCommand;
                            this.countDownLatch.countDown();
                        }
                     */
                    responseFuture.putResponse(null);
                    log.warn("send a request command to channel <" + addr + "> failed.");
                }
            });

            // 每次发送同步请求后,程序会执行 waitRespnse()方法,直到Netty接收Broker的返回结果
            /*
            *
            *
                public RemotingCommand waitResponse(final long timeoutMillis) throws                             InterruptedException {
                    this.countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
                    return this.responseCommand;
                }
            */
            RemotingCommand responseCommand = responseFuture.waitResponse(timeoutMillis);
            if (null == responseCommand) {
                if (responseFuture.isSendRequestOK()) {
                    throw new RemotingTimeoutException(RemotingHelper.parseSocketAddressAddr(addr), timeoutMillis,
                        responseFuture.getCause());
                } else {
                    throw new RemotingSendRequestException(RemotingHelper.parseSocketAddressAddr(addr), responseFuture.getCause());
                }
            }

            return responseCommand;
        } finally {
            this.responseTable.remove(opaque);
        }
    }

        

RocketMQ源码解析-topic创建机制 默认情况下,topic不用手动创建,当producer进行消息发送时,会从nameserver拉取topic的路由信息,如果topic的路由信息不存在,那么会默认拉取broker启动时默认创建好名为“TBW102”的Topic,这定义在org.apache.rocketmq.common.MixAll类中。这样TBW102 Topic的负载和一些默认的路由信息就会被自己创建的Topic使用。总结一下就是:通过使用系统内部的一个TBW102的Topic的配置来自动创建当前用户的要创建的自定义Topic。 阅读详情

相关推荐

RocketMQ 三种消息发送方式

producer向broker发送消息时指定消息发送成功及发送异常的回调方法,调用API后立即返回,producer发送消息线程不阻塞,消息发送成功或失败的回调任务在一个新的线程中执行。发送消息前进行校验,比如消息的内容长度不能为0、消息最大长度、消息必要的属性是否具备等(topic、消息体,生产组等)。Producer按选择算法从以上队列中选择一个进行消息发送,如果发送消息失败则在下次选择的时候会规避掉失败的broker。主题下的一条消息能被消费组下的所有消费者消费。.........

流楚丶格念的博客 8109

RocketMQ 消息发送流程

大家好,我是Leo。 今天聊一下RocketMQ消息发送,重试机制,故障延迟机制,获取路由机制,消息队列的选择 消息发送 关系图 首先放一下Broker Cluster,Broker,Topic,Queue的关系图。因为下文主要会沿着这四块进行梳理 发送的三种方式 消息发送的三种方式 同步:发送者向MQ发送一条消息后,一直等待服务器返回成功才继续下一个。 异步:发送者向MQ发送一条消息后,通过回调函数调用消息发布函数继续发送,主线程立即返回。 单向:发送者向MQ发送一条消息后,直接返回,不等待消息服务器

欢少的成长之路的博客 1646

2025软考信息安全工程师真题

2025信息安全工程师软考真题

qq_40424393的博客 1707

RocketMQ消息发送

RocketMQ消息发送 RocketMQ 支持3 种消息发送方式: 同步 (sync)、异步(async)、单向(oneway)。 同步:发送者向 MQ 执行发送消息API 时,同步等待,直到消息服务器返回发送结果。 异步:发送者向MQ 执行发送消息API 时,指定消息发送成功后的回调函数,然后调用消息发送API 后,立即返回,消息发送者线程不阻塞,直到运行结束,消息发送成功或失败的回调任务在一个新的线程中返回。 单向:消息发送者向MQ 执行发送消息API 时,直接返回,不等待消息服务器的结果

qq_27061805的博客 4847

金仓数据库KCM认证考试介绍【2025年4月更新】

金仓数据库认证资深专家KCM认证考试介绍

qq709869231的博客 3227

手把手教你:在openEuler 22.03上离线搞定OpenSSH 9.8升级(CentOS 7.9通用)

本文详细介绍了在openEuler 22.03和CentOS 7.9系统上离线升级OpenSSH 9.8的完整流程,包括准备工作、离线包获取、安装步骤、服务管理及回滚方案。特别针对无外网环境的企业服务器,提供安全可靠的离线升级解决方案,帮助运维人员有效提升系统安全性。

weixin_30682415的博客 192

Rocket MQ 从入门到实践

生产者将消息推送到队列之后,如果有消费者去消费这个主题上的消息,在队列上记录下不同消费者互不干扰不同的消费位置,它就可享有同一份消息。生产者将消息发送给Exchange交换机,交换机路由到不同的队列,不同的消费者针对不同的队列进行消费,实现简单、但是消息存储冗余。是否一致:如果消息的量级规模存在巨大差异,或者说消息的链路重要程度存在差异,则应该使用不同的主题进行隔离拆分。是否一致:不同类型的消息,如顺序消息和普通消息需要使用不同的主题进行拆分,无法通过tag标签进行分类。即不丢消息,但也有少量重复。

hukehukehukehuke的博客 1045

【NIFI】实现HANA->ORACLE数据同步

实现 HANA->ORACLE数据同步。

weixin_43159039的博客 1506

Rocket MQ 详解

开这个专栏主要之前实习的时候经常用到Rocket MQ,大厂使用的也比较多,主要讲解一些关键原理和概念。 介绍 定义:分布式消息中间件。MQ是消息队列的意思。 特点:低延迟、高并发、高可用、高可靠。 解释一下“高可用”:通常是指,通过设计减少系统不能提供服务的时间。 假设系统一直能够提供服务,我们说系统的可用性是100%。 如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。 核心概念 Topic:消息主题,我理解为与特定主题任务相关的一类消息。 生产者:生产消息.

strive for the best 的博客 1983

【卫星语音通信】神经网络语音编解码算法:AudioDec

最新研究表明,通过深度学习模型对语音信号进行智能压缩与重建,可在12 kbps码率下实现48 kHz采样率的高保真语音还原,其主观音质评分(MOS)可达3.9分(满分4.27分),远超传统参数编码技术。这意味着未来卫星电话的通话质量有望达到CD级水准,而蜂窝网络的语音业务带宽需求可降低60%以上,为蜂窝和卫星网络中的大规模物联网语音交互铺平道路。它的诞生为神经音频编解码技术带来了一次重要升级,有助于让未来实时语音交互更流畅、更清晰,也让我们进一步体验到人工智能与音频信号处理结合所带来的创新可能性。

u011376987的博客 1472

头歌操作系统 课后作业4.3:段页式内存管理 答案 无解析

头歌操作系统 课后作业4.3:段页式内存管理 答案 无解析

kercii的博客 7344

Rocket MQ

Broker 在收到消息后,通过 MessageStore 将消息存储到 commitLog 中,但是 consumer 在消费消息的时候是按照 topic+queue 的维度来拉取消息的。Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的Broker Name,不同的Broker Id来定义,BrokerId为0表示Master,非0表示Slave。

2401_84881237的博客 1309

【灰度共生矩阵(GLCM)原理及代码实现】

文章主旨详细介绍灰度共生矩阵(Gray-Level Co-occurrence Matrix, GLCM)的生成原理、核心特征量及其在图像纹理分析中的应用,并提供了可运行的Python代码实现。该网页是一篇理论结合实践的优秀技术文章。它不仅清晰地解释了GLCM这一经典纹理分析工具背后的数学原理,还提供了完整、可复现的代码,非常适合计算机视觉或图像处理领域的学习者和开发者入门并实践灰度共生矩阵。读者可以通过运行代码来直观理解GLCM如何工作,并提取图像的纹理特征。

blotemj.blog.youkuaiyun.com 179

18、Rocket MQ核⼼编程模型

这—章节,我们就来看下,在这两张图的基础上,如何编写合适的客户端代码,让我们在项⽬中⽤好。⽣产者要发送的消息⽐较多时,可以将多条消息合并成—个批量消息,—次性发送出去。因此,如果要重新发送消息,最好要带上唯—的系统标识,这样在消费者端,才能⾃⾏做幂等判断。⽽消息安全有两⽅⾯的要求,和⽤户⾃定义的属性,都是随着消息—起传递的,所以,消费者端是可以拿到消息的。的作⽤是可以在服务重启时,按照上—次消费的进度,处理后⾯没有消费过的消息。的机制,我们就可以在消息⽣产者发送完消息后,对发送失败的消息进⾏补救。

srrsheng的博客 1034

对MixPad精灵(触屏语音开关)进行解剖分析

概述 最近有点忙,已经很久没有更新文章了,对不起各位网友啦~ 这次对ORVIBO的新产品:MixPad精灵款的来个剖析,希望对大家有所帮助! 首先,我买了一台对应的设备,直接去官网采购,价格吗还算OK,400多的价格。 拆箱的过程我就不写了,简单的上个图就行了。 一、拆包: 主屏板包装盒(顶部): 主屏板包装盒(底部): 后盖电源部分无内容,我就不拍了,给优快云空间省点存储位置。 二、设备剖析开始 接下来,我们开始对设备进行剖析,步骤如下: 1、拆掉主屏板后盖板,...

LeeKwen的专栏 3941

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

基于Rocket MQ扩展的无限延迟消息队列

延迟队列固定时间间隔的基础上, 通过多次发送延迟消息, 达到任意延时时间组合计算. 通过反射的方式, 实现延迟业务逻辑的调用.简单而言, 就是在Rocket。

IT枫斗者的博客 2186

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Rocket MQ系列五 - 发送消息实践

发送普通消息 普通消息,也叫并发消息,是发送效率最高、使用场景最多的一类消息。发送普通消息的代码如下: public static void main(String[] args) throws MQClientException, InterruptedException { // 创建默认的生产者 DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");...

javaJasonjava的博客 1160

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

rocket mq的工作原理

##一、整体介绍 在RocketMQ里,有以下几个核心的模块:Producer,Consumer,Broker,NameSrv。他们之间的关系如下:  先简单了解一下各个模块的功能,下面会有章节详细介绍各个模块的功能。 Producer和Consumer很好理解,顾名思义就是生产者和消费者,生产者负责生产消息,消费者负责消费消息,这2块的逻辑都是由业务使用者定义的。 Br

七月流星 1万+

启动rocketmq_Linux下搭建Rocket MQ服务

本文介绍如何在Linux环境下搭建Rocket MQ服务,内容包含安装需要的环境,安装步骤,启动服务,模拟消息发送和接收,停止服务以及在安装过程中遇到的问题。还是老规矩,先跟着操作,操作完之后就基本都会了,如果还有疑问,请在留言区评论,我会及时回复ps:文中插入了命令,某些地方排版看起来会比较乱,但是操作还是很方便的依赖的环境Rocket MQ安装需要依赖JDK1.8和maven使用java -v...

weixin_31417135的博客 962

rocket mq 源码分析-Message 发送与接收

1、概述2、Producer 发送消息 DefaultMQProducer#send(Message)DefaultMQProducerImpl#sendDefaultImpl() DefaultMQProducerImpl#tryToFindTopicPublishInfo()MQFaultStrategy MQFaultStrategyLatencyFaultToleranc

七月流星 2646

Rocket MQ发送消息的三种方式初析

前言 MQ 发送消息有三种实现方式:可靠同步发送、可靠异步发送、单向(Oneway)发送。基于版本4.2.0+。注意:顺序消息只支持可靠同步发送。 可靠同步发送 原理:同步发送是指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。 场景:此种方式应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。 可靠异步发送 原理:异步发送是指发送方发出数...

FeelTouch Labs 5702

Rocket MQ如何保证消息顺序消费

文章参考: https://www.cnblogs.com/hzmark/p/orderly_message.html https://www.zhihu.com/question/30195969 消息中间件中的顺序消息 什么是顺序消息 有了上述的基础之后,我们回到本篇文章的主题中,聊一聊消息中间件中的顺序消息。 顺序消息(FIFO 消息)是 MQ 提供的一种严格按照顺序进行发布和消费的消息类型。顺序消息由两个部分组成:顺序发布和顺序消费。 顺序消息包含两种类型: 分区顺序:一个Part

qq_15045645的博客 3868

17、Rocket MQ快速实战以及核⼼概念详解

Rocket MQ是阿里巴巴开源的一个消息中间件,在阿里内部历经了双十一等很多高并发场景的考验,能够处理亿万级别的消息。2016年开源后捐赠给Apache,现在是Apache的—个顶级项目。早期阿里使用ActiveMQ ,但是,当消息开始逐渐增多后,ActiveMQ的IO性能很快达到了瓶颈。于是, 阿⾥开始关注Kafka。但是Kafka是针对日志收集场景设计的,他的高级功能并不是很贴合阿里的业务场景。

srrsheng的博客 1012

互联网公司都喜欢的消息队列,阿里Rocket MQ详细介绍

RocketMQ是⼀款阿⾥巴巴开源的消息中间件,在2017年9⽉份成为Apache的顶级项⽬,是国内⾸个互联⽹中间件在 Apache 上的顶级项⽬。

java_beautiful的博客 1092

Rocket MQ入门教程(MQ简介、集群搭建、收发消息)

文章目录一、MQ简介为什么使用MQMQ的优点和缺点各种MQ产品的比较二、RocketMQ快速入门准备工作安装RocketMQ启动RocketMQ测试RocketMQ关闭RocketMQ三、RocketMQ集群搭建各种角色的简介集群搭建的方式双主双从集群搭建工作流程准备工作broker配置文件修改启动脚本服务启动集群监控平台搭建四、消息发送案例基本案例发送同步消息发送异步消息发送单向消息消费消息负载均衡广播模式顺序消息顺序消息生产顺序消息消费延时消息批量发送过滤消息事务消息 一、MQ简介 为什么使用MQ 消息

m_awdawdw的博客 534
上一篇: Rocket MQ系列三 - 生产者启动流程
下一篇: Rocket MQ系列五 - 发送消息实践
geek-wmy
博客等级 码龄9年 322粉丝 126原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值