当前位置: 首页 > news >正文

rocketmq

🍓代码仓库

https://gitee.com/xuhx615/rocket-mqdemo.git

🍓基本概念

  • ⭐生产者(Producer):消息发布者
  • ⭐主题(Topic):topic用于标识同一类业务类型的消息
  • ⭐消息队列(MessageQueue):传输和存储消息的容器,是消息的最小存储单元
  • ⭐消费者(Consumer):消息订阅者
  • ⭐消费者组(ConsumerGroup):消息订阅者组,多个消费者之间进行负载均衡消费消息
  • nameServer:注册中心
  • Broker:消息中转站,用于接收生产者的消息并持久化,然后发送给对应的topic

🍓下载安装rocketmq

  1. ⭐前往官网https://rocketmq.apache.org下载rocketmq安装包和rocketmq图形化界面rocketmq Dashboard
  2. ⭐解压rocketmq安装包
    [root@Centos101 rocketmq]# unzip rocketmq-all-5.1.3-bin-release.zip
    
  3. ⭐修改namserver启动脚本runserverJVM内存参数(根据实际服务器资源设置,以下参数为学习时设置的参数)
     [root@Centos101 bin]# vi runserver.sh修改前:JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"修改后:JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
    
  4. ⭐启动nameserver
     [root@Centos101 bin]# ./mqnamesrv &
    
  5. ⭐查看nameserver启动日志
    [root@Centos101 bin]# tail -100f nohup.out
    
  6. ⭐修改broker启动脚本runbokerJVM内存参数
    [root@Centos101 bin]# vi runbroker.sh
    修改前:JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
    修改后:JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m"
    
  7. ⭐修改broker.conf配置文件
    默认配置
    #集群名称
    brokerClusterName = DefaultCluster
    #broker名称
    brokerName = broker-a
    #当前节点为主节点(主节点为0)
    brokerId = 0
    deleteWhen = 04
    fileReservedTime = 48
    brokerRole = ASYNC_MASTER
    flushDiskType = ASYNC_FLUSH新增以下配置
    #自动创建topic
    autoCreateTopicEnable = true
    #namesrvAddr地址
    namesrvAddr = 192.168.113.101:9876
    
  8. ⭐启动broker
    [root@Centos101 bin]# ./mqbroker -c ../conf/broker.conf &
    
  9. ⭐验证
    生产者:[root@Centos101 bin]# export NAMESRV_ADDR='192.168.113.101:9876'[root@Centos101 bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Producer
    消费者:[root@Centos101 bin]# export NAMESRV_ADDR='192.168.113.101:9876'[root@Centos101 bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
    
  10. ⭐关闭broker
    [root@Centos101 bin]# sh ./mqshutdown broker
    
  11. ⭐关闭nameserver
    [root@Centos101 bin]# sh ./mqshutdown namesrv
    

🍓rocketmq集群安装

  1. ⭐主机名配置

    192.168.113.101 Centos101
    192.168.113.102 Centos102
    192.168.113.103 Centos103
    
  2. ⭐免密登录

  3. ⭐关闭防火墙

  4. ⭐配置文件配置:

    • 📌2m-2s-async:2主2从异步刷盘(吞吐量较大,但消息可能会丢失)当生产者发送消息到主节点,主节点会直接给生产返回收到消息,然后异步同步给从节点
    • 📌2m-2s-sync:2主2从同步刷盘(吞吐量会下降,但消息会更安全)当生产者发送消息到主节点,主节点会同步同步给从节点,然后才给生产者返回收到消息
    • 📌2m-noslave:2主无从(单点故障),然后还可以直接配置broker.conf,进行单点环境配置
    • 📌集群搭建架构
         Centos101:部署nameserverCentos102:部署nameserver  broker-a,broker-b-sCentos103:部署nameserver  broker-b,broker-a-s
      
  5. ⭐集群启动

    • 📌nameserver服务启动
      分别在三个机器上启动nameserver
      [root@Centos101 bin]# ./mqnamesrv &
      [root@Centos102 bin]# ./mqnamesrv &
      [root@Centos103 bin]# ./mqnamesrv &
      
    • 📌broker服务启动
      在Centos102机器上启动broker(broker-a主节点和broker-b-s从节点)
      [root@Centos102 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-a.properties &
      [root@Centos102 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-b-s.properties &
      在Centos103机器上启动broker(broker-b主节点和broker-a-s从节点)
      [root@Centos103 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-b.properties &
      [root@Centos103 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-a-s.properties &
      
    • 📌验证
      在Centos102上模拟生产者
      [root@Centos102 bin]# export NAMESRV_ADDR='Centos101:9876;Centos102:9876;Centos103:9876'
      [root@Centos102 bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Producer
      在Centos103上模拟消费者
      [root@Centos103 bin]# export NAMESRV_ADDR='Centos101:9876;Centos102:9876;Centos103:9876'
      [root@Centos103 bin]# ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
      

🍓安装rocketmq图形化管理界面:dashboard

修改application.properties
rocketmq.config.namesrvAddr=Centos101:9876;Centos102:9876;Centos103:9876
修改logback.xml日志路径

🍓rocketmq的local模式启动,新增proxy模块(5.0后支持的模块)

引入 Proxy 模块后,Proxy 承担了协议适配、权限管理、消息管理等计算功能,Broker 则更加专注于存储。这样存储和计算相分离,在云原生环境下可以更好地进行资源调度。

[root@Centos102 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-a.properties --enable-proxy &
[root@Centos103 bin]# ./mqbroker -c ../conf/2m-2s-async/broker-b.properties --enable-proxy &

🍓部署模型

在这里插入图片描述

🍓消息发送过程

在这里插入图片描述
在这里插入图片描述

🍓消息存储过程

在这里插入图片描述

🍓生产者

生产者分为同步生产者和异步生产者以及单项生产者

  • ⭐同步生产者:生产者将消息推送Broker,等待Broker返回推送确认,再推送下一个
    1、可靠性要求高
    2、数据量级少
    3、实时响应
    import org.apache.rocketmq.client.producer.DefaultMQProducer;
    import org.apache.rocketmq.client.producer.SendResult;
    import org.apache.rocketmq.client.producer.SendStatus;
    import org.apache.rocketmq.common.message.Message;DefaultMQProducer producer = null;try {producer = new DefaultMQProducer("syncProducer");producer.setNamesrvAddr("192.168.113.101:9876");producer.start();for (int i = 0; i < 2; i++) {String body = "Hello zhang " + i;//参数一:主题、参数二:过滤、参数三:消息内容Message message = new Message("rocketmq_syncDemo","tag", body.getBytes("UTF-8"));//同步发送SendResult result = producer.send(message);String msgId = result.getMsgId();SendStatus sendStatus = result.getSendStatus();logger.info("{}消息发送状态为{}", msgId, sendStatus);}} catch (Exception e) {logger.error("生产者发送消息失败!" ,e);} finally {if (producer != null) {producer.shutdown();}}
    
  • ⭐异步生产者:生产者将消息推送Broker,不会等待Broker返回推送确认,直接推送下一个,但是会回调方法告诉生产者消息是否发送成功。
    	try {//异步发送producer.send(message, new SendCallback() {@Overridepublic void onSuccess(SendResult sendResult) {String msgId = sendResult.getMsgId();SendStatus sendStatus = sendResult.getSendStatus();logger.info("{}消息发送状态为{}", msgId, sendStatus);}@Overridepublic void onException(Throwable throwable) {logger.error("消息发送失败", throwable);}});} catch (Exception e) {logger.error("生产者发送消息失败!" ,e);} finally {//异步发送不应该关闭,关闭了便无法回调方法}
    
  • ⭐单项生产者:生产者将消息推送Broker,不会等待Broker返回推送确认,直接推送下一个。
    	//单向发送producer.sendOneway(message);
    

🍓消费者

消费者分为推模式和拉模式

  • ⭐推模式:消费者等待Broker把消息推送过来(被动消费)

    import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
    import org.apache.rocketmq.client.consumer.listener.*;
    import org.apache.rocketmq.client.exception.MQClientException;
    import org.apache.rocketmq.common.message.MessageExt;DefaultMQPushConsumer consumer = null;try {consumer = new DefaultMQPushConsumer("group_rocketmq_syncDemo");consumer.setNamesrvAddr("192.168.113.101:9876");//参数一:topic、参数二:过滤(*表示不过滤)consumer.subscribe("rocketmq_syncDemo", "*");//设置消息监听//MessageListenerConcurrently 并发消费监听consumer.setMessageListener(new MessageListenerConcurrently() {public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {list.forEach(item -> {try {logger.info("消息消费成功!消息ID={},消息内容:{}", item.getMsgId(), new String(item.getBody(), "UTF-8"));} catch (Exception e) {logger.error("消息消费失败!", e);}});return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;}});//消费者启动consumer.start();} catch (MQClientException e) {logger.error("消费者消费异常!",e);}
    
  • ⭐拉模式:消费者主动去Broker上拉取消息(主动消费)

    import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
    import org.apache.rocketmq.client.consumer.PullResult;
    import org.apache.rocketmq.client.consumer.store.ReadOffsetType;
    import org.apache.rocketmq.client.exception.MQClientException;
    import org.apache.rocketmq.common.message.MessageQueue;try {DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("group_rocketmq_asyncDemo");consumer.setNamesrvAddr("192.168.113.101:9876");Set<String> topicSet = new HashSet<>();topicSet.add("rocketmq_asyncDemo");consumer.setRegisterTopics(topicSet);consumer.start();//主题遍历while (true) {consumer.getRegisterTopics().forEach(item -> {try {Set<MessageQueue> messageQueues = consumer.fetchSubscribeMessageQueues(item);//消息队列messageQueues.forEach(item2 -> {try {long offset = consumer.getOffsetStore().readOffset(item2, ReadOffsetType.READ_FROM_MEMORY);if (offset < 0) {offset = consumer.getOffsetStore().readOffset(item2, ReadOffsetType.READ_FROM_STORE);}if (offset < 0) {offset = consumer.maxOffset(item2);}if (offset < 0) {offset = 0;}PullResult result = consumer.pull(item2, "*", offset, 32);if (result != null) {switch (result.getPullStatus()) {case FOUND:{result.getMsgFoundList().forEach(item3 -> {try {logger.info("消息消费成功!消息ID={},消息内容:{}", item3.getMsgId(), new String(item3.getBody(), "UTF-8"));consumer.updateConsumeOffset(item2, result.getNextBeginOffset());} catch (Exception e) {logger.error("遍历消息信息失败!" , e);}});break;}case NO_NEW_MSG:{logger.info("没有最新消息!");break;}case NO_MATCHED_MSG: {logger.info("没有匹配的消息!");break;}case OFFSET_ILLEGAL: {logger.error("偏移量非法,当前偏移量为{}", offset);break;}}}} catch (Exception e) {logger.error("遍历消息队列失败!", e);}});} catch (MQClientException e) {logger.error("遍历主题失败!", e);}});}} catch (MQClientException e) {logger.error("消息拉取失败!", e);}
    
    • 📌随机获取消息队列消息
      DefaultLitePullConsumer consumer = null;
      try {consumer = new DefaultLitePullConsumer("group_rocketmq_asyncDemo");consumer.setNamesrvAddr("192.168.113.101:9876");consumer.subscribe("rocketmq_asyncDemo", "*");consumer.start();while (true) {List<MessageExt> messageExtList = consumer.poll();messageExtList.forEach(item -> {try {logger.info("获取消息成功!消息队列ID={},消息ID={},消息内容{}", item.getQueueId(),item.getMsgId(), new String(item.getBody(), "UTF-8"));} catch (Exception e) {logger.error("获取消息异常!",e);}});}
      } catch (MQClientException e) {logger.error("获取消息异常!",e);
      } finally {if (consumer != null) {consumer.shutdown();}
      }
      
    • 📌指定消息队列获取消息
      	//指定第一个消息队列消费consumer.seek(messageQueueList.get(0), 10);
      

🍓顺序消息

  • ⭐生产者需要将有序消息发送到同一个队列

  • ⭐消费者push模式,通过加锁的方式,使得一个队列同时只有一个消费者,每隔一段时间就会延长锁的时间(有超时机制),直到整个队列的消息全部消费

  • ⭐消费者pull模式,只要消费者自己能保证消息顺序消费就行

  • ⭐消费线程数需设置为1

  • ⭐生产者代码

    //i 队列序号
    for (int i = 0; i < 5; i++) {//j 消息序号for (int j = 0; j < 100; j++) {Message message = new Message("rocketmq_orderDemo", "tag", ("Hello world!" + j).getBytes("UTF-8"));producer.send(message, new MessageQueueSelector() {/*** * @param list 队列集合* @param message 消息 (send函数第一个参数)* @param o 队列序号 (send函数第三个参数)* @return 消息队列*/@Overridepublic MessageQueue select(List<MessageQueue> list, Message message, Object o) {return list.get(Integer.parseInt(o.toString()));}}, i);}
    }
    
  • ⭐消费者代码

    //MessageListenerOrderly有序消息监听(不要使用并发消费监听)
    consumer.setMessageListener(new MessageListenerOrderly() {@Overridepublic ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {list.forEach(item -> {try {logger.info("消息接收成功!消息队列={},消息ID={},消息内容={}", item.getQueueId(), item.getMsgId(), new String(item.getBody(), "UTF-8"));} catch (Exception e) {logger.error("消息接收异常!", e);}});return ConsumeOrderlyStatus.SUCCESS;}
    });
    

🍓广播消息

生产者:

 //设置为广播模式consumer.setMessageModel(MessageModel.BROADCASTING);

🍓延时消息

生产者:

//1-18 对应 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h (消费者会跟生产者设置的时间延迟接收消息)
//message.setDelayTimeLevel(3);//设置自定义时间,单位毫秒
message.setDelayTimeMs(10000L);

🍓批量消息

  • ⭐优点:减少网络OA,提高吞吐量

  • 限制:

    • 消息大小不能超过4M
    • 相同的topic
    • 相同的waitStoreMsgOk
    • 不能是延迟消息、事务消息等
  • ⭐切割消息工具

    /*** 消息集合切割* 消息大小 = 消息长度 + 主题长度 + 消息自定义属性key长度 + 消息自定义属性val长度 + 20(日志空余)* @author xuhaixiang* @date 2023-09-10*/
    public class ListSplitter implements Iterator<List<Message>> {/*** 消息大小限制 1MB*/private static final int SIZE_LIMIT = 10 * 1000;/*** 消息集合*/private final List<Message> messageList;/*** 当前索引*/private int currentIndex;public ListSplitter(List<Message> messageList) {this.messageList = messageList;}@Overridepublic boolean hasNext() {return currentIndex < messageList.size();}@Overridepublic List<Message> next() {int nextIndex = currentIndex;int totalSize = 0;for (; nextIndex < messageList.size(); nextIndex++) {Message message = messageList.get(nextIndex);int messageSize = message.getBody().length + message.getTopic().length();Map<String, String> properties = message.getProperties();for (String key : properties.keySet()) {String val = properties.get(key);messageSize += key.length() + val.length();}messageSize += 20;totalSize += messageSize;if (totalSize > SIZE_LIMIT) {nextIndex = nextIndex - 1;break;}}List<Message> result = messageList.subList(currentIndex, nextIndex);currentIndex = nextIndex;return result;}
    }
    
  • ⭐消息批量发送

    List<Message> messages = new ArrayList<>();
    for (int i = 0; i < 2000; i++) {String body = i + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quasi exercitationem laudantium repellendus quisquam aspernatur est neque quidem vitae nostrum! Quia voluptatibus vitae tempore! Repellendus quam aspernatur, nam neque hic esse!";//参数一:主题、参数二:过滤、参数三:消息内容Message message = new Message("rocketmq_syncDemo","tag", body.getBytes("UTF-8"));messages.add(message);
    }
    ListSplitter listSplitter = new ListSplitter(messages);
    while (listSplitter.hasNext()) {List<Message> messageList = listSplitter.next();SendResult result = producer.send(messageList);String msgId = result.getMsgId();SendStatus sendStatus = result.getSendStatus();logger.info("{}消息发送状态为{}", msgId, sendStatus);
    }
    

🍓过滤消息

  • tag过滤

    • 📌生产者
      String[] tagArr = {"tagA", "tagB", "tagC"};
      for (int i = 0; i < 2; i++) {for (String tag : tagArr) {String body = tag + ", Hello zhang " + i;//参数一:主题、参数二:过滤、参数三:消息内容Message message = new Message("rocketmq_syncDemo",tag, body.getBytes("UTF-8"));SendResult result = producer.send(message);String msgId = result.getMsgId();SendStatus sendStatus = result.getSendStatus();logger.info("{}消息发送状态为{}", msgId, sendStatus);}
      }
      
    • 📌消费者·
      //参数一:topic、参数二:过滤(*表示不过滤),多个tag可以使用||
      consumer.subscribe("rocketmq_syncDemo", "tagA || tagC");
      
  • SQL过滤

    • 📌生产者
      message.putUserProperty("type", "elg_" + i);
      
    • 📌消费者(必须推模式)
       //过滤方式二(注意该sql里面字段是区分大小写的)//sql过滤方式,borker配置文件必须设置属性enablePropertyFilter=true,并且消费者必须是推模式//另外消息过滤行为是在broker端进行的,可以提升网络传输性能,但是会增加服务器的压力(将过滤sql推送给broker)consumer.subscribe("rocketmq_syncDemo", MessageSelector.bySql("TAGS is not null and TAGS in ('tagA','tagC') and type = 'elg_0'"));
      

🍓事务消息

  • ⭐事务消息是分布式系统中保证最终一致性的两阶段提交的消息实现。他可以保证本地事务执行与消息发送两个操作的原子性,也就是两个操作一起成功或者一起失败。

  • ⭐事务消息机制的关键是在发送消息时会将消息转为一个half消息,并存入rocketmq内部的一个Topic(RMQ_SYS_TRANS_HALF_TOPIC),这个topic对消费者是不可见的。再经过一系列事务检查通过后,再将消息转存到目标topic,这样消费者就可见了。

  • ⭐事务消息实现原理主要通过两个发送阶段和一个确认阶段来实现

  • ⭐本地事务消息执行器(本地事务执行和本地事务回查,用于向rocketmq发送提交、回滚、无状态三种结果)

    import org.apache.rocketmq.client.producer.LocalTransactionState;
    import org.apache.rocketmq.client.producer.TransactionListener;
    import org.apache.rocketmq.common.message.Message;
    import org.apache.rocketmq.common.message.MessageExt;
    import org.apache.rocketmq.logging.org.slf4j.Logger;
    import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;/*** 本地事务实现类* @author xuhaixiang* @date 2023-09-11*/
    public class TransactionListenerImpl implements TransactionListener {/*** 日志对象*/private static  final Logger logger = LoggerFactory.getLogger(TransactionListenerImpl.class);/*** 本地事务执行* @param message* @param o* @return*/@Overridepublic LocalTransactionState executeLocalTransaction(Message message, Object o) {String tags = message.getTags();logger.info("{}本地事务执行", tags);if ("tagA".equals(tags)) {//tagA允许发送return LocalTransactionState.COMMIT_MESSAGE;}if ("tagB".equals(tags)) {//tagB消息回滚return LocalTransactionState.ROLLBACK_MESSAGE;}//其他消息无状态,无状态消息会进行本地事务回查return LocalTransactionState.UNKNOW;}/*** 本地事务回查* @param messageExt* @return*/@Overridepublic LocalTransactionState checkLocalTransaction(MessageExt messageExt) {String tags = messageExt.getTags();logger.info("{}本地事务回查", tags);if ("tagC".equals(tags)) {//tagC本地事务回查允许发送return LocalTransactionState.COMMIT_MESSAGE;}return LocalTransactionState.UNKNOW;}
    }
    
  • ⭐生产者

    TransactionMQProducer producer = null;
    try {producer = new TransactionMQProducer("transactionProductor");producer.setNamesrvAddr("192.168.113.101:9876");//开启异步线程,用于异步执行本地事务执行和回查两个动作ExecutorService service = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS ,new ArrayBlockingQueue<>(20000), new ThreadFactory(){@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);thread.setName("transaction");return thread;}});producer.setExecutorService(service);//设置本地事务执行器producer.setTransactionListener(new TransactionListenerImpl());producer.start();String[] tags = {"tagA", "tagB", "tagC", "tagD", "tagE"};for (int i = 0; i < 10; i++) {for (String tag : tags) {Message message = new Message("rocketmq_transactionDemo", tag, (tag + " Hello world!" + i).getBytes("UTF-8"));TransactionSendResult result = producer.sendMessageInTransaction(message, null);logger.info("消息发送成功!消息ID={}" + result.getMsgId());}}//让生产者存活一段时间可以回调本地事务执行和本地事务回查Thread.sleep(60000);
    } catch (Exception e) {logger.error("消息发送异常!", e);
    } finally {if (producer != null) {producer.shutdown();}
    }
    
  • ⭐消费者。事务与消费没有任何关系,消费者正常消费消息就行。

🍓如何保证消息不丢失

消息丢失的几种情况:

  1. 生产者将消息发送给broker,当网络发生异常,消息可能会丢失
    解决:消息发送后会有ack返回,当我们发现消息发送失败,可以做一个重试机制
  2. 消费者拿到消息,会立即发送ack告诉broker收到,但是在接下来处理消息时发生了异常,可能会导致消息丢失,消息无法重新消费
    解决:先处理完消息之后,再返回ackbroker
  3. broker存储消息阶段,异步刷盘可能会出现问题导致消息丢失
    解决:使用同步刷盘机制;集群模式采用同步复制

🍓消息持久化机制

rocketmq的消息持久化机制是指将消息存储在磁盘上,以确保消息能够可靠存储和检索
rocketmq消息持久化涉及以下三个角色

  • CommitLog消息存储文件
    • 📌存储方式:
      • 🍁同步刷盘:消息存储到内存,再从内存存储到commitLog,然后返回生产者ack
      • 🍁异步刷盘:消息存储到内存,然后返回生产者ack,再异步存储到commitLog
    • 📌文件固定大小1G,超过则新开辟一个文件
  • ConsumeQueue
    存储commitLog当前读取的偏移量、消息大小、tags
  • IndexFile
    存储消息自定义的属性、与之对应的消息偏移量、时间参数、下一个Index偏移量

🍓rocketmq保证消息有序

  • ⭐生产者需要将有序消息发送到同一个队列
  • ⭐消费者push模式,通过加锁的方式,使得一个队列同时只有一个消费者,每隔一段时间就会延长锁的时间(有超时机制),直到整个队列的消息全部消费
  • ⭐消费者pull模式,只要消费者自己能保证消息顺序消费就行
  • ⭐消费线程数需设置为1

相关文章:

rocketmq

&#x1f353;代码仓库 https://gitee.com/xuhx615/rocket-mqdemo.git &#x1f353;基本概念 ⭐生产者(Producer)&#xff1a;消息发布者⭐主题&#xff08;Topic&#xff09;&#xff1a;topic用于标识同一类业务类型的消息⭐消息队列&#xff08;MessageQueue&#xff09…...

JAVA成员变量首字母小写,第二个字母大写报错问题(原因:Lombok与Spring冲突)

1、问题现象&#xff1a; JAVA类里定义成员变量使用首字母小写&#xff0c;第二个字母大写 Getter Setter public class BrandQueryObject extends QueryObject{private String pName; }结果页面报错&#xff0c;无法找到类型为 cn.wolfcode.ssm.query.BrandQueryObject 的对象…...

Python入门教程 |Python 错误和异常

Python3 错误和异常 作为 Python 初学者&#xff0c;在刚学习 Python 编程时&#xff0c;经常会看到一些报错信息&#xff0c;在前面我们没有提及&#xff0c;这章节我们会专门介绍。 Python 有两种错误很容易辨认&#xff1a;语法错误和异常。 Python assert&#xff08;断…...

API商品接口对接使用:从理论到实践

随着电子商务的飞速发展&#xff0c;API商品接口已成为现代电子商务应用程序不可或缺的一部分。通过API商品接口&#xff0c;开发者可以轻松地从其他应用程序或服务中获取商品信息&#xff0c;实现快速、高效的电子商务功能。本文将探讨API商品接口的概念、对接使用的方法以及一…...

解决stable diffusion webui1.6 wd1.4 tagger加载失败的问题

由于webui源码的变化&#xff0c;需要修改两个地方的import 1.tagger/ui.py # 第十行 # from webui import wrap_gradio_gpu_call # 原代码 from modules.call_queue import wrap_gradio_gpu_call1.preload.py # 第4行开始 # from modules.shared import models_path # 原…...

Python学习-实现简单的http服务

基于Python实现一个简单的HttpServer,当用户在浏览器中输入IP地址:8000时&#xff0c;则会返回index.html页面内容&#xff0c;访问其它信息&#xff0c;则会返回错误信息(404) """ httpserver v1.0 1.获取来自浏览器的请求&#xff0c; 2.判断如果请求内容是 …...

#循循渐进学51单片机#变量进阶与点阵LED#not.6

1、掌握变量的作用域及存储类别。 局部变量 函数内部声明的变量&#xff0c;只在函数内部有效&#xff0c;在本函数以外是不能使用的&#xff0c;叫局部变量。 全局变量 在函数外部声明的变量就是全局变量&#xff0c;一个源程序可以包含一个或多个函数&#xff0c;全局变量…...

访问者模式

图片转载自 #include<iostream> using namespace std; #include<list> /*模板工厂单例化&#xff0c;所有的商品被注册进工厂中*/ /*访问者模式&#xff08;行为型模式&#xff09; 访问者&#xff0c;被访问者 visit accept 让访问变成一种操作&#xff0c;不同…...

epoll 的实现

epoll 这么好&#xff0c;为什么迟至 2.6 版本的 kernel 才支持(epoll manual: The epoll API was introduced in Linux kernel 2.5.44.)&#xff1f;2.4 版本的 kernel 不支持 epoll&#xff1f; 原因很简单&#xff0c;epoll 没什么神奇的。在早期没有太多的并发连接要处理&…...

怎么用excel管理固定资产

在当今的数字时代&#xff0c;我们已经习惯了使用各种电子工具来提高我们的生产力。其中&#xff0c;Excel无疑是一个强大的工具&#xff0c;它不仅可以帮助我们处理数据&#xff0c;还可以用来进行复杂的计算和分析。然而&#xff0c;你可能不知道的是&#xff0c;Excel也可以…...

记录crack某IDE插件过程

声明&#xff1a;本文仅记录学习过程&#xff0c;已对关键位置脱敏处理&#xff0c;未提供任何工具&#xff0c;请支持正版。 反编译jar包 使用cfr进行对插件核心jar包MyBxxxxxx-obfuss.jar进行反编译&#xff0c;在本地生成a.txt。 java -jar cfr-0.152.jar MyBxxxx-obfuss.…...

Android DEX相关,ART加载OAT文件

android .dex文件,对于Android DEX文件详细说明 Android dex、odex、oat、vdex、art区别 Android下的DEX文件和SO文件梳理总结 Android[art]-Android dex&#xff0c;odex&#xff0c;oat&#xff0c;vdex&#xff0c;art文件结构学习总结 第四章 常见的 Android 文件格式&…...

laravel框架 - 安装初步使用学习 composer安装

一、什么是laravel框架 Laravel框架可以开发各种不同类型的项目&#xff0c;内容管理系统&#xff08;Content Management System&#xff0c;CMS&#xff09;是一种比较典型的项目&#xff0c;常见的网站类型&#xff08;如门户、新闻、博客、文章等&#xff09;都可以利用CM…...

API实战教程:使用身份证OCR识别API构建一个应用

1. 引言 你是否曾经想过&#xff0c;只需拍一张身份证的照片&#xff0c;就能自动读取上面的所有信息&#xff1f;今天&#xff0c;我们要介绍的就是这样一个神奇的工具&#xff1a;身份证OCR识别API。不管你是技术小白还是初学者&#xff0c;跟着我们的步骤&#xff0c;你都可…...

前端-layui动态渲染表格行列与复杂表头合并

说在前面&#xff1a; 最近一直在用layui处理表格 写的有些代码感觉还挺有用的&#xff0c;顺便记录下来方便以后查看使用&#xff1b; HTML处代码 拿到id 渲染位置表格 <div class"layui-table-body salaryTable"><table class"layui-table" i…...

IDM(Internet Download Manager)下载器2024最新版本如何下载?

IDM&#xff08;Internet Download Manager&#xff09;下载器能够兼容支持多种浏览器进行文件下载&#xff0c;很多时候只要复制一个地址IDM的下载弹窗就自动弹出来&#xff0c;有时候不需要下载的时候也会弹&#xff0c;时间久了就会感觉很烦&#xff0c;不过这个问题其实可以…...

前端综合练手小项目

导读 本篇文章主要以小项目的方式展开&#xff0c;其中给出的代码中均包含详细地注释&#xff0c;大家可以参照理解。下面4个小项目中均包含有 HTML、CSS、JavaScript 等相关知识&#xff0c;可以拿来练手&#xff0c;系统提升一下自己的前端开发能力。 废话少说&#xff0c;…...

接口优化1

接口优化 文章目录 接口优化1. 内容概述2. 集成RabbitMQ2.1 下载2.2 SpringBoot集成RabbitMQ 快速入门1.相关配置2.创建发送者者和接收者 2.3 rabbitmq四种交换模式2.4 秒杀接口优化 1. 内容概述 核心思路:减少对数据库的访问&#xff0c;利用Redis的高并发特性来实现。 系统初…...

【无公网IP内网穿透】 搭建Emby媒体库服务器并远程访问「家庭私人影院」

目录 1.前言 2. Emby网站搭建 2.1. Emby下载和安装 2.2 Emby网页测试 3. 本地网页发布 3.1 注册并安装cpolar内网穿透 3.2 Cpolar云端设置 3.3 Cpolar内网穿透本地设置 4.公网访问测试 5.结语 1.前言 在现代五花八门的网络应用场景中&#xff0c;观看视频绝对是主力…...

QML android 采集手机传感器数据 并通过udp 发送

利用 qt 开发 安卓 app &#xff0c;采集手机传感器数据 并通过udp 发送 #ifndef UDPLINK_H #define UDPLINK_H#include <QObject> #include <QUdpSocket> #include <QHostAddress>class UdpLink : public QObject {Q_OBJECT public:explicit UdpLink(QObjec…...

stableDiffusion安装

下载git 下载python-3.10.6版本 clone git至本地 使用git clone命令 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 更换pip源为为百度镜像 pip config --global set global.index-url https://mirror.baidu.com/pypi/simple 最后的镜像源链接 阿里云 h…...

QT基础教程(QPushButton及信号与槽)

文章目录 前言一、信号与槽二、QPushButton总结 前言 本篇文章来带大家学习QPushbutton和信号与槽&#xff0c;其中信号与槽是QT中的核心也是比较重要的一个知识点。 资料合集地微信公众号&#xff1a;优质程序猿一、信号与槽 信号与槽&#xff08;Signals and Slots&#x…...

Android 实战项目分享(一)用Android Studio绘制贝塞尔曲线的艺术之旅

一、项目概述 欢迎来到创意之源&#xff01;我们精心打造的绘图应用程序将带你进入一个充满艺术和技术的奇妙世界。通过使用Android Studio&#xff0c;我们实现了绘制贝塞尔曲线的功能&#xff0c;让你能够轻松创作出令人惊叹的艺术作品。不论你是热爱绘画的大学生还是渴望学习…...

Windows系统关机后自动重启的解决方法

打开控制面板&#xff0c;找到【电源选项】&#xff1b; 方式一&#xff0c;打开Windows终端&#xff08;管理员&#xff09;&#xff0c;输入“powercfg /h on”然后回车&#xff1b; 方式二&#xff0c;键盘按下开始键&#xff0c;搜索“控制面板”然后打开&#xff1b; 点击…...

微服务如何改变软件开发:实战经验与最佳实践分享

文章目录 什么是微服务&#xff1f;微服务实战经验1. 定义明确的服务边界2. 使用API网关3. 自动化部署和持续集成4. 监控和日志记录 微服务最佳实践1. 文档和通信2. 弹性设计3. 安全性4. 版本控制5. 监控和警报 微服务的未来 &#x1f389;欢迎来到架构设计专栏~微服务如何改变…...

安装深度(Deepin)系统

Deepin系统安装 Deepin是和Ubuntu一样&#xff0c;是一个基于Debian的Linux的发型版本。 Deepin相对于Ubuntu&#xff0c;Deepin更适合中国用户的使用习惯。 一 官网工具制作启动盘 制作启动盘、和安装系统&#xff0c;操作非常简单&#xff0c;nice&#xff01; 官网提供了…...

Leetcode: 645.错误的集合 题解【超详细】

题目 集合 s 包含从 1 到 n 的整数。不幸的是&#xff0c;因为数据错误&#xff0c;导致集合里面某一个数字复制了成了集合里面的另外一个数字的值&#xff0c;导致集合 丢失了一个数字 并且 有一个数字重复 。 给定一个数组 nums 代表了集合 S 发生错误后的结果。 请你找出重复…...

闲鱼自动化软件——筛选/发送系统 V22已经测试完毕

更新 因为闲鱼版本更新&#xff0c;以及闲鱼整个程序维护记录&#xff0c;又增加了一些优化和提升的代码&#xff0c;所以又一次在整体上更新了一版闲鱼的此款软件。 主要更新点&#xff1a; 1、添加显示自定义按钮&#xff0c;可以自动显示最新数据&#xff0c;也可以手动翻…...

数学建模__动态规划

动态规划就是&#xff0c;将任务每一步均记录下来&#xff0c;以便将来重复使用时能够直接调用 问题描述&#xff1a;给定n个物品&#xff0c;每个物品的重量是Wi,价值是Vi&#xff0c;但是背包最多能装下capacity重量的物品&#xff0c;问我们如何选择才能利益最大化。 这里涉…...

【IoT】生产制造:锅仔片上机做 SMT 加工吗?

目录 简介 锅仔片 简介 由于最近做产品用到了锅仔按键&#xff0c;由于单品用量过多&#xff0c;但是成品锅仔按键价格又太高&#xff0c;不适合量产。 这个时候就想到了锅仔片&#xff0c;问题又来了&#xff0c;锅仔片是否可以上机呢&#xff1f; 答案是肯定的。 锅仔片…...

杭州建设网站/常州seo博客

概述 Unix 域套接字是一种客户端和服务器在单主机上的 IPC 方法。Unix 域套接字不执行协议处理&#xff0c;不需要添加或删除网络报头&#xff0c;无需验证和&#xff0c;不产生顺序号&#xff0c;无需发送确认报文&#xff0c;比因特网域套接字的效率更高。Unix 域套接字提供字…...

专做服装的网站/网络推广公司服务内容

Win10系统已经跟大家见面3年左右了&#xff0c;越来越多的用户在当初充满质疑的争论中慢慢接受了&#xff0c;在使用的过程中难免会出现这样那样的问题&#xff0c;我们知道&#xff0c;win10系统本身就比较大&#xff0c;会占用一部分内存空间&#xff0c;再加上平时是用的过程…...

WordPress做的网站源代码/网上有卖网站链接的吗

1&#xff0c;在wind搭建VisualSVN Server Manager 由于好几次启动server都找不到项目分支。解决办法&#xff1a;卸载重装之后项目出现&#xff0c;服务器项目不会消失。 2&#xff0c;sql更新语句 update DyMyOrderWTCE&#xff08;表1&#xff09; dy set dy.cesdzt (se…...

可以用来做简单的网络验证的网站/国际形势最新消息

方法区知识概括栈 堆 方法区的交互关系方法区的理解设置方法区大小与 OOM方法区的内部结构方法区演进细节方法区的垃圾回收运行时数据区总结栈 堆 方法区的交互关系 从线程共享与否的角度来看&#xff1a; ThreadLocal&#xff1a;如何保证多个线程在并发环境下的安全性&…...

网站开发接单平台/竞价培训

作用域闭包递归 &#xff08;自己调自己&#xff09; 简单闭包 function parent() {var x parentfunction son() {var x sonreturn x}return son() } parent() //son闭包写法&#xff1a; /*写法一*/ function parent() {var x parentreturn function son() {var x …...

长沙官网网站建设/直播回放老卡怎么回事

基础练习 杨辉三角形 时间限制&#xff1a;1.0s 内存限制&#xff1a;256.0MB问题描述杨辉三角形又称Pascal三角形&#xff0c;它的第i1行是(ab)i的展开式的系数。    它的一个重要性质是&#xff1a;三角形中的每个数字等于它两肩上的数字相加。    下面给出了杨辉三角…...