Rocket MQ系列二 - 生产者原理

RocketMQ从入门到精通——消息发送 消息发送概述 RocketMQ支持三种方式发送消息——同步,异步,Oneway。同步发送及producer消息发送后,同步等待直至broker响应;异步发送即需要消息发送成功后立即返回不等待,等待发送结束后回调函数会被调用。Oneway方式发送完成后不等待结果返回,也不不指定回调函数,消息有可能发送失败。 从性能方面来讲,三种发送方式从高到低依次是Oneway发送,异步发送,同步发送。 从可靠性方面来讲,三种发送方式从高到低依次是同步发送,异步发送,Oneway发送。 消息结构 消息类Message中包含t 阅读详情

生产者原理

生产者概述

        发送消息的一方被称为生产者,他在整个RocketMQ的生产和消费体系中扮演的角色如图所示:

        生产者组:一个逻辑概念,在使用生产者实例的时候需要指定一个组名。一个生产者组可以生产多个topic的消息。

        生产者实例:一个生产者组部署多个进程,每个进程都可以成为一个生产者实例。

        Topic:主题名字,一个Topic由若干Queue组成。

        RocketMQ客户端中的生产者有两个独立实现类

org.apache.rocketmq.client.producer.DefaultMQProducer
org.apache.rocketmq.client.producer.TransactionMQProducer

        前者用于生产普通消息、顺序消息、单向消息、批量消息、延迟消息,后者主要用于生产事务消息。

消息结构和消息类型

        消息类的核心字段定义如下:

public class Message implements Serializable {
    private static final long serialVersionUID = 8445773977080406428L;

    private String topic;
    private int flag;
    private Map<String, String> properties;
    private byte[] body;
    private String transactionId;

    public Message() {
    }

    public Message(String topic, byte[] body) {
        this(topic, "", "", 0, body, true);
    }

    public Message(String topic, String tags, String keys, int flag, byte[] body, boolean waitStoreMsgOK) {
        this.topic = topic;
        this.flag = flag;
        this.body = body;

        if (tags != null && tags.length() > 0) {
            this.setTags(tags);
        }

        if (keys != null && keys.length() > 0) {
            this.setKeys(keys);
        }

        this.setWaitStoreMsgOK(waitStoreMsgOK);
    }

    public Message(String topic, String tags, byte[] body) {
        this(topic, tags, "", 0, body, true);
    }

    public Message(String topic, String tags, String keys, byte[] body) {
        this(topic, tags, keys, 0, body, true);
    }

    public void setKeys(String keys) {
        this.putProperty(MessageConst.PROPERTY_KEYS, keys);
    }

    void putProperty(final String name, final String value) {
        if (null == this.properties) {
            this.properties = new HashMap<String, String>();
        }

        this.properties.put(name, value);
    }

    void clearProperty(final String name) {
        if (null != this.properties) {
            this.properties.remove(name);
        }
    }

    public void putUserProperty(final String name, final String value) {
        if (MessageConst.STRING_HASH_SET.contains(name)) {
            throw new RuntimeException(String.format(
                "The Property<%s> is used by system, input another please", name));
        }

        if (value == null || value.trim().isEmpty()
            || name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException(
                "The name or value of property can not be null or blank string!"
            );
        }

        this.putProperty(name, value);
    }

    public String getUserProperty(final String name) {
        return this.getProperty(name);
    }

    public String getProperty(final String name) {
        if (null == this.properties) {
            this.properties = new HashMap<String, String>();
        }

        return this.properties.get(name);
    }

    public String getTopic() {
        return topic;
    }

    public void setTopic(String topic) {
        this.topic = topic;
    }

    public String getTags() {
        return this.getProperty(MessageConst.PROPERTY_TAGS);
    }

    public void setTags(String tags) {
        this.putProperty(MessageConst.PROPERTY_TAGS, tags);
    }

    public String getKeys() {
        return this.getProperty(MessageConst.PROPERTY_KEYS);
    }

    public void setKeys(Collection<String> keys) {
        StringBuilder sb = new StringBuilder();
        for (String k : keys) {
            sb.append(k);
            sb.append(MessageConst.KEY_SEPARATOR);
        }

        this.setKeys(sb.toString().trim());
    }

    public int getDelayTimeLevel() {
        String t = this.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL);
        if (t != null) {
            return Integer.parseInt(t);
        }

        return 0;
    }

    public void setDelayTimeLevel(int level) {
        this.putProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(level));
    }

    public boolean isWaitStoreMsgOK() {
        String result = this.getProperty(MessageConst.PROPERTY_WAIT_STORE_MSG_OK);
        if (null == result) {
            return true;
        }

        return Boolean.parseBoolean(result);
    }

    public void setWaitStoreMsgOK(boolean waitStoreMsgOK) {
        this.putProperty(MessageConst.PROPERTY_WAIT_STORE_MSG_OK, Boolean.toString(waitStoreMsgOK));
    }

    public void setInstanceId(String instanceId) {
        this.putProperty(MessageConst.PROPERTY_INSTANCE_ID, instanceId);
    }

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        this.flag = flag;
    }

    public byte[] getBody() {
        return body;
    }

    public void setBody(byte[] body) {
        this.body = body;
    }

    public Map<String, String> getProperties() {
        return properties;
    }

    void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

    public String getBuyerId() {
        return getProperty(MessageConst.PROPERTY_BUYER_ID);
    }

    public void setBuyerId(String buyerId) {
        putProperty(MessageConst.PROPERTY_BUYER_ID, buyerId);
    }

    public String getTransactionId() {
        return transactionId;
    }

    public void setTransactionId(String transactionId) {
        this.transactionId = transactionId;
    }

}

        Topic:主题名字,可以通过RocketMQ Console创建

        Flag:目前没用

        Propertise:消息扩展信息,Tag、keys、延迟级别都保存在这里

        Body:消息体,字节数组。需要注意生产者使用什么编码,消费者也必须使用相同的编码解码,否则会产生乱码。

        setKeys():设置消息的key,多个key可以用MessageConst.KEY_SEPARATOR分隔或者直接用另一个重载方法。如果Broker中messageIndexEnable=true 则会根据key创建消息的hash索引,帮助用户进行快速查询。

        setTags():消息过滤的标记,用户可以订阅某个Topic的某些Tag,这样Broker只会吧订阅了topic-tag的消息发送个消费者。

        setDelayTimeLevel():设置延迟级别,延迟多久消费者可以消费。

        putUserProperty():如果还有其他扩展信息,可以存放在这里,内部是一个Map,重复调用会覆盖旧值。

        

        RocketMQ支持普通消息、分区有序消息、全局有序消息、延迟消息和事务消息

        普通消息:普通消息也称为并发消息,和传统的队列相比,并发消息没有顺序,但是生产消费都是并行进行的,单机性能可达十万级别的TPS。

        分区有序消息:与kafka中的分区类似,把一个Topic消息分为多个分区保存和消费,在一个分区内的消息就是传统的队列,遵循FIFO的原则。

        全局有序消息:如果把一个topic的分区数设置为1,那么该topic中的消息就是单分区,所有消息都遵循FIFO的原则。

        延迟消息:消息发送后,消费者要在一定时间后,或者指定某个时间点才可以消费。在没有延迟消息时,基本的做法是基于定时计划任务调度,定时发送消息。在RocketMQ中只需要在发送消息时设置延迟级别即可实现。

        事务消息:主要涉及分布式事务,即需要保证在多个操作同时成功或者同时失败时,消费者才能消费消息。RocketMQ通过发送half消息、处理本地事务、提交消息或者回滚消息优雅地实现分布式事务。

生产者高可用

        通常,我们希望不管Broker、Namesrv出现什么情况,发送消息都不要出现未知状态或者消息丢失。在消息发送的过程中,客户端、Broker、Namesrv都有可能发生服务器损坏,掉电等各种故障。当这些故障发生时,RockerMQ是怎么处理的呢?

1. 客户端保证机制

        第一种保证机制:重试机制。RocketMQ支持同步、异步发送,不管哪种方式都可以在配置失败后重试,如果单个Broker发生故障,重试会选择其他Broker保证消息正常发送。

        配置项retryTimesWhenSendFailed表示同步重试次数,默认为2次,加上正常发送1次,总共3次机会。

        同步发送的重试代码可以参考 

org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl

        每次发送失败后,除非发送被打断否则都会执行重试代码。同步发送重试代码如下:

    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);
    }

        异步发送重试代码可以参考

org.apache.rocketmq.client.impl.MQClientAPIImpl

        代码如下:

    private void sendMessageAsync(
        final String addr,
        final String brokerName,
        final Message msg,
        final long timeoutMillis,
        final RemotingCommand request,
        final SendCallback sendCallback,
        final TopicPublishInfo topicPublishInfo,
        final MQClientInstance instance,
        final int retryTimesWhenSendFailed,
        final AtomicInteger times,
        final SendMessageContext context,
        final DefaultMQProducerImpl producer
    ) throws InterruptedException, RemotingException {
        final long beginStartTime = System.currentTimeMillis();
        this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
            @Override
            public void operationComplete(ResponseFuture responseFuture) {
                long cost = System.currentTimeMillis() - beginStartTime;
                RemotingCommand response = responseFuture.getResponseCommand();
                if (null == sendCallback && response != null) {

                    try {
                        SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response, addr);
                        if (context != null && sendResult != null) {
                            context.setSendResult(sendResult);
                            context.getProducer().executeSendMessageHookAfter(context);
                        }
                    } catch (Throwable e) {
                    }

                    producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), false);
                    return;
                }

                if (response != null) {
                    try {
                        SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response, addr);
                        assert sendResult != null;
                        if (context != null) {
                            context.setSendResult(sendResult);
                            context.getProducer().executeSendMessageHookAfter(context);
                        }

                        try {
                            sendCallback.onSuccess(sendResult);
                        } catch (Throwable e) {
                        }

                        producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), false);
                    } catch (Exception e) {
                        producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), true);
                        onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
                            retryTimesWhenSendFailed, times, e, context, false, producer);
                    }
                } else {
                    producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), true);
                    if (!responseFuture.isSendRequestOK()) {
                        MQClientException ex = new MQClientException("send request failed", responseFuture.getCause());
                        onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
                            retryTimesWhenSendFailed, times, ex, context, true, producer);
                    } else if (responseFuture.isTimeout()) {
                        MQClientException ex = new MQClientException("wait response timeout " + responseFuture.getTimeoutMillis() + "ms",
                            responseFuture.getCause());
                        onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
                            retryTimesWhenSendFailed, times, ex, context, true, producer);
                    } else {
                        MQClientException ex = new MQClientException("unknow reseaon", responseFuture.getCause());
                        onExceptionImpl(brokerName, msg, timeoutMillis - cost, request, sendCallback, topicPublishInfo, instance,
                            retryTimesWhenSendFailed, times, ex, context, true, producer);
                    }
                }
            }
        });
    }

        重试是在通信层异步发送完成的,当operationComplete()方法返回的response值为null时,会重新执行重试代码。返回值response为null通常是因为客户端收到TCP请求解包失败,或者没有找到匹配的request。

        生产者配置项retryTimesWhenSendAsyncFailed表示异步重试的次数,默认为2次,加上正常发送的1次,总共有3次发送机会。

        第二种保证机制:客户端容错。RocketMQ Client 会维护一个“Broker-发送延迟”关系,根据这个关系选择一个发送延迟级别较低的Broker来发送消息,这样能最大限度地利用Broker的能力,剔除已经宕机、不可用或者发送延迟级别较高的Broker,尽量保证消息的正常发送。

        这种机制主要体现在发送消息时如何选择Queue,源代码在 sendDefautImpl() 方法调用的 selectOneMessageQueue()方法中

       

    public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
        if (this.sendLatencyFaultEnable) {
            try {
                // 第一步
                int index = tpInfo.getSendWhichQueue().incrementAndGet();
                for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) {
                    int pos = Math.abs(index++) % tpInfo.getMessageQueueList().size();
                    if (pos < 0)
                        pos = 0;
                    MessageQueue mq = tpInfo.getMessageQueueList().get(pos);
                    if (latencyFaultTolerance.isAvailable(mq.getBrokerName()))
                        return mq;
                }

                // 第二步
                final String notBestBroker = latencyFaultTolerance.pickOneAtLeast();
                int writeQueueNums = tpInfo.getQueueIdByBroker(notBestBroker);
                if (writeQueueNums > 0) {
                    final MessageQueue mq = tpInfo.selectOneMessageQueue();
                    if (notBestBroker != null) {
                        mq.setBrokerName(notBestBroker);
                        mq.setQueueId(tpInfo.getSendWhichQueue().incrementAndGet() % writeQueueNums);
                    }
                    return mq;
                } else {
                    latencyFaultTolerance.remove(notBestBroker);
                }
            } catch (Exception e) {
                log.error("Error occurred when selecting message queue", e);
            }

            // 第三步
            return tpInfo.selectOneMessageQueue();
        }
        
        return tpInfo.selectOneMessageQueue(lastBrokerName);
    }

        sendLatencyFaultEnable:发送延迟容错开关,默认是关闭,如果开关打开了,会触发发送延迟容错机制来选择发送Queue。

        发送Queue时如何选择呢?

        第一步:获取一个在延迟上可以接受,并且和上次发送相同的Broker。首先获取一个自增序号index,通过取模获取Queue的位置下标pos。如果pos对应的Broker的延迟时间可以接受,并且是第一次发送,或者和上次发送的Broker相同,则将Queue放回。

        第二步:如果第一步没有选中一个Broker,则选择一个延迟较低的Broker。

        第三步:如果第一、二步都没有选中一个Broker,则随机选择一个Broker。

        第二段代码主要包括一个随机选择方法

tpInfo.selectOneMessageQueue(lastBrokerName);

        该方法的功能就是随机选择一个Broker,具体实现如下:

       

    public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
        if (lastBrokerName == null) {
            // 第一步
            return selectOneMessageQueue();
        } else {
            // 第二步
            for (int i = 0; i < this.messageQueueList.size(); i++) {
                int index = this.sendWhichQueue.incrementAndGet();
                int pos = Math.abs(index) % this.messageQueueList.size();
                if (pos < 0)
                    pos = 0;
                MessageQueue mq = this.messageQueueList.get(pos);
                if (!mq.getBrokerName().equals(lastBrokerName)) {
                    return mq;
                }
            }
            // 第三步
            return selectOneMessageQueue();
        }
    }

        第一步:如果没有上次使用的Broker作为参考,那么随机选择一个Broker。

        第二步:如果存在上次使用的Broker,就选择非上次使用的Broker,目的是均匀地分散Broker压力。

        第三步:如果第一、二步都没有选中一个Broker,则采用兜底方案,随机选择一个Broker。

        在执行如上代码时,需要Broker和发送延迟的数据作为判断的一句,这些数据是怎么来的呢?

        客户端在发送消息后,会调用 updateFaultItem() 方法来更新当前接收消息的Broker的延迟情况,这些主要逻辑都在MQFaultStrategy 类中实现,延迟策略有一个标准接口LatencyFaultTolerance,我们可以通过这个接口实现自定义的延迟策略。

2. Broker端保证

        数据同步方式保证,同步复制和异步复制。同步复制是指消息发送到Master Broker后,同步到Slave Broker才算发送成功;异步复制是指消息发送到Master Broker,即为发送成功。在生产环境中,建议至少部署2个Master和1个Slave,下面分为几种情况详细描述:

(1)1个Slave掉电。Broker同步复制时,生产第一次发送失败,重试到另一组Broker后成功,Broker异步复制时,生产正常不受影响

(2)2个Slave掉电。Broker同步复制时,生产失败,Broker异步复制时,生产正常不受影响。

(3)1个Master掉电。Broker同步复制时,生产第一次失败,重试到另一组Broker后成功,Broker异步复制时的做法与同步复制相同。

(4)2个Master掉电。全部生产失败。

(5)同一组Master和Slave掉电。Broker同步复制时,生产第一次发送失败,重试到另一组Broker后成功,Broker异步复制时不受影响。

(6)2组机器都掉电。全部生产失败。

综上所述,想要做到绝对的高可靠,将Broker配置的主从同步进行复制即可,只要生产者收到消息保存成功的反馈,消息就肯定不会丢失。绝大部分场景都可以配置主从异步复制,这样效率极高。

Rocket MQ 集群搭建 集群搭建(三台机器56 57 58) 免密登录(56机器) 搭建(2主2从) 配置第一组broker-a 配置第二组broker-b 启动集群 ① 修改三个节点上的bin/runserver.sh,调整里面的jvm内存配置 ② 直接在三个节点上启动nameServer ③ 启动broker ④ 验证 搭建管理控制台 ① 下载地址:https://github.com/apache/rocketmq-externals ② 进入rocket-console目录,使用maven 阅读详情

相关推荐

ADS RFpro 射频阻抗仿真步骤

导入器件后,在库里面选取器件的对应模型,如图所示我们选取10pf 系统自带的村田模型。选取网络上的器件,拖入到下面component Models。导入成功后,截取需要仿真的区域(不截取仿真时间会非常长),可以生成对应如下原理图,通过原理图继续调整仿真。图上找到需要仿真链路上的网络,右键设置为信号。的叠层信息,按照PCB板厂提供信息填写完整。选择仿真的频率范围和频点数,生成如下图的RFPro仿真界。,然后再把GND也添加到下面。按图设置截取需要仿真的部分。添加成功后 网络就有了,15 双击run开始仿真。

m0_72954480的博客 3216

RocketMQ发送消息报错 The name or value of property can not be null or blank string!

异常日志:org.springframework.messaging.MessagingException: The name or value of property can not be null or blank string!; nested exception is java.lang.IllegalArgumentException: The name or value of property can not be null or blank string! at org.apache.rock

xzh_blog 1406

PyQt5 + HFSS:给你的仿真脚本做个专属GUI界面(零基础搭建指南)

本文详细介绍了如何使用PyQt5为HFSS仿真脚本创建专属GUI界面,适合零基础用户快速上手。通过Python二次开发,实现参数可视化调整、进度实时监控等功能,大幅提升团队协作效率。文章涵盖环境配置、界面设计、HFSS集成到打包部署的全流程,是仿真工程师提升工作效率的实用指南。

weixin_42535720的博客 185

Rocketmq(二) - 架构详解

Apache RocketMQ 是一个分布式消息和流媒体平台,它由四个部分组成:名称服务器、代理、生产者和消费者。它们中的每一个都可以水平扩展以杜绝单点故障,基础架构

编程是一门实践技术 1084

从零开始,手把手教你用RTL代码设计一个简单的8位CPU(附状态图与ALU设计)

本文详细介绍了如何从零开始设计一个简单的8位CPU,包括状态机设计、ALU实现与RTL编码实战。通过具体的指令集分析、状态图设计和Verilog代码示例,帮助读者深入理解CPU工作原理,并掌握RTL代码编写技巧。特别适合计算机系统学习者和硬件设计爱好者。

weixin_30847063的博客 320

华为S5700三层交换机VLAN配置避坑指南:为什么你的VLAN间无法互通?

本文针对华为S5700三层交换机VLAN间无法互通的典型故障,提供深度排障指南。文章从数据转发原理入手,系统梳理了从物理链路、VLAN配置、VLANIF接口状态、路由表到ARP表、MTU及安全策略等全链路检查点,并给出了清晰的排查命令与流程,帮助网络工程师快速定位并解决VLAN间路由问题,实现稳定互通。

tt34567的博客 872

【rocketmq系列】【四】【消息发送】

消息队列RocketMQ版提供三种方式来发送普通消息:同步(Sync)发送、异步(Async)发送和单向(Oneway)发送。 了解点 发送方式的原理 应用场景 消息队列如何进行负载 消息发送如何实现高可用 批量消息发送如何实现一致性 3种发送方式 同步发送 原理 同步发送是指消息发送方发出一条消息后,会在收到服务端返回响应之后才发下一条消息的通讯方式。 应用场景 应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。 原理 同步发送是指消息发送方发出一条消息后,

weixin_43958091的博客 574

PaddleOCR SVTRv2中文识别模型训练全流程:从数据准备到推理部署

本文详细介绍了基于PaddleOCR的SVTRv2中文识别模型从数据准备、模型训练到推理部署的全流程实战。SVTRv2凭借其单视觉Transformer架构和分层混合机制,在中文文字识别任务上实现了高精度与效率的平衡。文章重点解析了数据工程、训练调优技巧及部署优化方案,帮助开发者构建定制化的OCR解决方案。

weixin_29194817的博客 287

RocketMQ 消息结构和消息类型

生产者 Producer 概述和消息结构与消息类型

jiaomubai的博客 3886

QSPI Flash的原理与QSPI时序的Verilog实现

本节主要是讨论QSPI(Quad SPI,四线SPI总线)的相关内容。我的开发板上有一片型号是W25Q128BV的Quad SPI Flash存储器,本文将以它为例子来说明QSPI操作的一些内容。

Go Forward Forever! 4165

代谢组数据分析(四):多种差异分析方法筛选代谢物标记物

本文详细介绍了代谢组学中常用的差异分析方法,包括倍数变化法、T检验、VIP值在OPLS-DA中的应用。通过这些方法,研究者能够筛选出在不同组别间具有显著差异的代谢物,为疾病诊断和治疗提供线索。文章还提供了一个整合的R函数run_metabolomeDA,便于研究人员进行一站式差异分析,并展示了如何生成火山图来可视化结果。

专注生信领域 6770

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

【AUTOSAR-RTE】-1-聊一聊RTE(Run-Time Environment)

RTE(Run-Time Environment)是AUTOSAR ECU架构的核心。

「汽车电子助手」的博客 6502

Rocket MQ 从入门到实践

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

hukehukehukehuke的博客 1045

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Spring boot 3.x 整合 Rocket MQ 遇到的那些事

spring boot 3 整合 Rocket MQ 遇到的那些事

HongSH945的博客 1717

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Rocket MQ 详解

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

strive for the best 的博客 1983

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

20、Rocket MQ集群⾼级特性

⼆、主从节点切换的⾼可⽤集群⼀。

srrsheng的博客 1211

rocket mq的工作原理

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

七月流星 1万+

Rocket MQ系列三 - 生产者启动流程

DefaultMQProducer是RocketMQ中默认的生产者实现,DefaultMQProducer的类之间的继承关系如下所示: 可以看到这个生产者在实现时包含生产者的操作和配置属性,这是典型的类对象设计。 以下是一些核心属性: namesrvAddr:继承自ClientConfig,表示RocketMQ集群的Namesrv地址,如果是多个则用分号分开。 clientIP:使用的客户端程序所在机器的IP地址,支持IPv4和IPv6,IPv4排除了本地的环回地址和私有内网...

javaJasonjava的博客 1326

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

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

java_beautiful的博客 1092

18、Rocket MQ核⼼编程模型

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

srrsheng的博客 1034

启动rocketmq_Linux下搭建Rocket MQ服务

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

weixin_31417135的博客 962

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

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

srrsheng的博客 1012

Rocket MQ「2」架构

一 名词解释 Message:消息,Rocket MQ中传递信息的载体; Producer:生产者,即消息的发布者,负责生产并发送消息; Producer Instance:生产者实例,表示一个生产者具体对象; Producer Group: 生产者组,即生产者集群,由一个或多个相同生产者实例组成; Customer:消费者,也称为订阅者,负责接收被消费消息; Customer Instance:消费者实例,表示一个消费者的具体对象; Customer Group:消费者组,即消费者集群,由

说淑人的所思所想 312

Rocket MQ 学习

RocketMQ学习笔记 rocketmq 是一款分布式,队列模型的开源消息件 。 一、RocketMQ 的特性 原生分布式 俩种消息拉取 严格消息顺序 特有的分布式协调器 亿级消息堆积 组(group) RocketMQ的基本概念 Producer : 消息生产者,负责产生消息,一般由业务系统负责产生消息。 ​ Consumer:消息消费者,负责消费消息,一般是后台异步系统负责异步消费。 ​ Push Consumer:封装消息拉取,消费进程和内部 *

勿忘初心的博客 1189
上一篇: 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、付费专栏及课程。

余额充值