rocketmq
🍓代码仓库
https://gitee.com/xuhx615/rocket-mqdemo.git
🍓基本概念
- ⭐生产者(
Producer):消息发布者 - ⭐主题(
Topic):topic用于标识同一类业务类型的消息 - ⭐消息队列(
MessageQueue):传输和存储消息的容器,是消息的最小存储单元 - ⭐消费者(
Consumer):消息订阅者 - ⭐消费者组(
ConsumerGroup):消息订阅者组,多个消费者之间进行负载均衡消费消息 - ⭐
nameServer:注册中心 - ⭐
Broker:消息中转站,用于接收生产者的消息并持久化,然后发送给对应的topic
🍓下载安装rocketmq
- ⭐前往官网
https://rocketmq.apache.org下载rocketmq安装包和rocketmq图形化界面rocketmq Dashboard - ⭐解压
rocketmq安装包[root@Centos101 rocketmq]# unzip rocketmq-all-5.1.3-bin-release.zip - ⭐修改
namserver启动脚本runserver的JVM内存参数(根据实际服务器资源设置,以下参数为学习时设置的参数)[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" - ⭐启动
nameserver[root@Centos101 bin]# ./mqnamesrv & - ⭐查看
nameserver启动日志[root@Centos101 bin]# tail -100f nohup.out - ⭐修改
broker启动脚本runboker的JVM内存参数[root@Centos101 bin]# vi runbroker.sh 修改前:JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g" 修改后:JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m" - ⭐修改
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 - ⭐启动
broker[root@Centos101 bin]# ./mqbroker -c ../conf/broker.conf & - ⭐验证
生产者:[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 - ⭐关闭
broker[root@Centos101 bin]# sh ./mqshutdown broker - ⭐关闭
nameserver[root@Centos101 bin]# sh ./mqshutdown namesrv
🍓rocketmq集群安装
-
⭐主机名配置
192.168.113.101 Centos101 192.168.113.102 Centos102 192.168.113.103 Centos103 -
⭐免密登录
-
⭐关闭防火墙
-
⭐配置文件配置:
- 📌
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
- 📌
-
⭐集群启动
- 📌
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();} } -
⭐消费者。事务与消费没有任何关系,消费者正常消费消息就行。
🍓如何保证消息不丢失
消息丢失的几种情况:
- 生产者将消息发送给
broker,当网络发生异常,消息可能会丢失
解决:消息发送后会有ack返回,当我们发现消息发送失败,可以做一个重试机制 - 消费者拿到消息,会立即发送
ack告诉broker收到,但是在接下来处理消息时发生了异常,可能会导致消息丢失,消息无法重新消费
解决:先处理完消息之后,再返回ack给broker broker存储消息阶段,异步刷盘可能会出现问题导致消息丢失
解决:使用同步刷盘机制;集群模式采用同步复制
🍓消息持久化机制
rocketmq的消息持久化机制是指将消息存储在磁盘上,以确保消息能够可靠存储和检索
rocketmq消息持久化涉及以下三个角色
- ⭐
CommitLog消息存储文件- 📌存储方式:
- 🍁同步刷盘:消息存储到内存,再从内存存储到
commitLog,然后返回生产者ack - 🍁异步刷盘:消息存储到内存,然后返回生产者ack,再异步存储到
commitLog
- 🍁同步刷盘:消息存储到内存,再从内存存储到
- 📌文件固定大小
1G,超过则新开辟一个文件
- 📌存储方式:
- ⭐
ConsumeQueue
存储commitLog当前读取的偏移量、消息大小、tags值 - ⭐
IndexFile
存储消息自定义的属性、与之对应的消息偏移量、时间参数、下一个Index偏移量
🍓rocketmq保证消息有序
- ⭐生产者需要将有序消息发送到同一个队列
- ⭐消费者
push模式,通过加锁的方式,使得一个队列同时只有一个消费者,每隔一段时间就会延长锁的时间(有超时机制),直到整个队列的消息全部消费 - ⭐消费者
pull模式,只要消费者自己能保证消息顺序消费就行 - ⭐消费线程数需设置为1
相关文章:
rocketmq
🍓代码仓库 https://gitee.com/xuhx615/rocket-mqdemo.git 🍓基本概念 ⭐生产者(Producer):消息发布者⭐主题(Topic):topic用于标识同一类业务类型的消息⭐消息队列(MessageQueue)…...
JAVA成员变量首字母小写,第二个字母大写报错问题(原因:Lombok与Spring冲突)
1、问题现象: JAVA类里定义成员变量使用首字母小写,第二个字母大写 Getter Setter public class BrandQueryObject extends QueryObject{private String pName; }结果页面报错,无法找到类型为 cn.wolfcode.ssm.query.BrandQueryObject 的对象…...
Python入门教程 |Python 错误和异常
Python3 错误和异常 作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,在前面我们没有提及,这章节我们会专门介绍。 Python 有两种错误很容易辨认:语法错误和异常。 Python assert(断…...
API商品接口对接使用:从理论到实践
随着电子商务的飞速发展,API商品接口已成为现代电子商务应用程序不可或缺的一部分。通过API商品接口,开发者可以轻松地从其他应用程序或服务中获取商品信息,实现快速、高效的电子商务功能。本文将探讨API商品接口的概念、对接使用的方法以及一…...
解决stable diffusion webui1.6 wd1.4 tagger加载失败的问题
由于webui源码的变化,需要修改两个地方的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时,则会返回index.html页面内容,访问其它信息,则会返回错误信息(404) """ httpserver v1.0 1.获取来自浏览器的请求, 2.判断如果请求内容是 …...
#循循渐进学51单片机#变量进阶与点阵LED#not.6
1、掌握变量的作用域及存储类别。 局部变量 函数内部声明的变量,只在函数内部有效,在本函数以外是不能使用的,叫局部变量。 全局变量 在函数外部声明的变量就是全局变量,一个源程序可以包含一个或多个函数,全局变量…...
访问者模式
图片转载自 #include<iostream> using namespace std; #include<list> /*模板工厂单例化,所有的商品被注册进工厂中*/ /*访问者模式(行为型模式) 访问者,被访问者 visit accept 让访问变成一种操作,不同…...
epoll 的实现
epoll 这么好,为什么迟至 2.6 版本的 kernel 才支持(epoll manual: The epoll API was introduced in Linux kernel 2.5.44.)?2.4 版本的 kernel 不支持 epoll? 原因很简单,epoll 没什么神奇的。在早期没有太多的并发连接要处理&…...
怎么用excel管理固定资产
在当今的数字时代,我们已经习惯了使用各种电子工具来提高我们的生产力。其中,Excel无疑是一个强大的工具,它不仅可以帮助我们处理数据,还可以用来进行复杂的计算和分析。然而,你可能不知道的是,Excel也可以…...
记录crack某IDE插件过程
声明:本文仅记录学习过程,已对关键位置脱敏处理,未提供任何工具,请支持正版。 反编译jar包 使用cfr进行对插件核心jar包MyBxxxxxx-obfuss.jar进行反编译,在本地生成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,odex,oat,vdex,art文件结构学习总结 第四章 常见的 Android 文件格式&…...
laravel框架 - 安装初步使用学习 composer安装
一、什么是laravel框架 Laravel框架可以开发各种不同类型的项目,内容管理系统(Content Management System,CMS)是一种比较典型的项目,常见的网站类型(如门户、新闻、博客、文章等)都可以利用CM…...
API实战教程:使用身份证OCR识别API构建一个应用
1. 引言 你是否曾经想过,只需拍一张身份证的照片,就能自动读取上面的所有信息?今天,我们要介绍的就是这样一个神奇的工具:身份证OCR识别API。不管你是技术小白还是初学者,跟着我们的步骤,你都可…...
前端-layui动态渲染表格行列与复杂表头合并
说在前面: 最近一直在用layui处理表格 写的有些代码感觉还挺有用的,顺便记录下来方便以后查看使用; HTML处代码 拿到id 渲染位置表格 <div class"layui-table-body salaryTable"><table class"layui-table" i…...
IDM(Internet Download Manager)下载器2024最新版本如何下载?
IDM(Internet Download Manager)下载器能够兼容支持多种浏览器进行文件下载,很多时候只要复制一个地址IDM的下载弹窗就自动弹出来,有时候不需要下载的时候也会弹,时间久了就会感觉很烦,不过这个问题其实可以…...
前端综合练手小项目
导读 本篇文章主要以小项目的方式展开,其中给出的代码中均包含详细地注释,大家可以参照理解。下面4个小项目中均包含有 HTML、CSS、JavaScript 等相关知识,可以拿来练手,系统提升一下自己的前端开发能力。 废话少说,…...
接口优化1
接口优化 文章目录 接口优化1. 内容概述2. 集成RabbitMQ2.1 下载2.2 SpringBoot集成RabbitMQ 快速入门1.相关配置2.创建发送者者和接收者 2.3 rabbitmq四种交换模式2.4 秒杀接口优化 1. 内容概述 核心思路:减少对数据库的访问,利用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.前言 在现代五花八门的网络应用场景中,观看视频绝对是主力…...
QML android 采集手机传感器数据 并通过udp 发送
利用 qt 开发 安卓 app ,采集手机传感器数据 并通过udp 发送 #ifndef UDPLINK_H #define UDPLINK_H#include <QObject> #include <QUdpSocket> #include <QHostAddress>class UdpLink : public QObject {Q_OBJECT public:explicit UdpLink(QObjec…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
