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

RocketMQTemplate 实现消息发送

代码托管于gitee:easy-rocketmq

文章目录

    • 一、前置工作
    • 二、消费者
    • 三、生产者
      • 1. 普通消息
      • 2. 过滤消息
      • 3. 同步消息
      • 4. 延时消息
      • 5. 批量消息
      • 6. 异步消息
      • 7. 单向消息
      • 8. 顺序消息
      • 9. 事务消息
        • 概要
        • Demo
        • 源码解读

一、前置工作

1、导入依赖

<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.1.1</version>
</dependency>

2、编写配置

rocketmq:name-server: 47.96.232.192:9876producer:# 生产组名group: demoGroup# 消息发送超时时间send-message-timeout: 3000# 消息体阈值,4k以上会压缩compress-message-body-threshold: 4096# 在同步模式下发送失败之前在内部执行的最大重试次数。retry-times-when-send-failed: 3# 在异步模式下发送失败之前在内部执行的最大重试次数。retry-times-when-send-async-failed: 3# 消息阈值,最大4MB,在 4KB 之内性能最佳max-message-size: 4096

二、消费者

实现RocketMQListener接口,使用 @RocketMQMessageListener 注册监听,需指定消费者组和Topic。

@Component
@RocketMQMessageListener(consumerGroup = "demo-consumer-group",  // consumerGroup:消费者组名topic = "Demo",                         // topic:订阅的主题selectorExpression = "*",               // selectorExpression:控制可以选择的消息,可以使用SelectorType.SQL92语法。设置为 * 时,表示全部。messageModel = MessageModel.CLUSTERING  // messageModel: 控制消息模式。MessageModel.CLUSTERING:负载均衡;MessageModel.BROADCASTING:广播模式
)
public class MqConsumerListener implements RocketMQListener<String> {@Overridepublic void onMessage(String message) {System.out.println("消费消息-" + message);}}

测试一下消费情况~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZp5iWqs-1677066712694)(RocketMQTemplate 实现消息发送.assets/image-20230215202513669.png)]

三、生产者

1. 普通消息

普通消息无返回值,只负责发送消息⽽不等待服务器回应且没有回调函数触发。

@Override
public void convertAndSend(D destination, Object payload) throws MessagingException {convertAndSend(destination, payload, (Map<String, Object>) null);
}

发送一个普通消息吧~

@SpringBootTest
class RocketmqTemplateDemoApplicationTests {@Autowiredprivate RocketMQTemplate rocketMQTemplate;/*** 普通消息无返回值,只负责发送消息⽽不等待服务器回应且没有回调函数触发*  - 参数一:topicName:tags,主题:标签,可单Topic不指定Tag*  - 参数二:消息体*/@Testpublic void sendBaseMsg() {rocketMQTemplate.convertAndSend("Demo:base","普通消息测试");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-THzerNj5-1677067369640)(RocketMQTemplate 实现消息发送.assets/image-20230215195854038.png)]

源码

接下来我们一步一步点进去~

在这里插入图片描述

此时我们发现其调用的最终调用了 doSend 方法,在其实现类RocketMQTemplate中调用了syncSend()方法,该方法以同步的方式发送消息并且返回值SendResult。但 doSend 方法的返回值类型是void,并不返回SendResult。

在这里插入图片描述

我们发现该syncSend()底层是调用了DefaultMQProducer的send方法,这里关于DefaultMQProducer就不做过多讲解了~

2. 过滤消息

convertAndSend还有另外一个可携带属性的重载方法,可以通过给消息携带属性的方式,消费者利用sql92的方式实现消息过滤~

@Override
public void convertAndSend(D destination, Object payload, @Nullable Map<String, Object> headers)throws MessagingException {convertAndSend(destination, payload, headers, null);
}

发送携带属性的消息吧~

发送若干条消息携带属性a,属性值分别为0~9。消费者消息过滤仅消费携带属性a且属性值在[6,9]范围内的(包含)

/*** 过滤消息*/
@GetMapping("/filter")
public void sendFilterMsg() {for (int i = 0; i < 10; i++) {HashMap<String, Object> harder = new HashMap<>(1);harder.put("a", String.valueOf(i));rocketMQTemplate.convertAndSend("Demo:filter","过滤消息测试" + i, harder);}
}

通过sql92过滤消息

1、修改选择消息模式为 SelectorType.SQL92,默认模式是SelectorType.TAG。

selectorType = SelectorType.SQL92

2、编写过滤sql:

selectorExpression = "a BETWEEN 6 AND 9"
@Component
@RocketMQMessageListener(consumerGroup = "demo-consumer-group",      // consumerGroup:消费者组名topic = "Demo",                             // topic:订阅的主题selectorType = SelectorType.SQL92,          // selectorType:那种模式选择消息selectorExpression = "a BETWEEN 6 AND 9",   // selectorExpression:控制可以选择的消息,可以使用SelectorType.SQL92语法。设置为 * 时,表示全部。messageModel = MessageModel.CLUSTERING      // messageModel: 控制消息模式。MessageModel.CLUSTERING:负载均衡;MessageModel.BROADCASTING:广播模式
)
public class MqConsumerListener implements RocketMQListener<Object> {@Overridepublic void onMessage(Object message) {System.out.println("消费消息-" + message);}}

biu发送消息~
在这里插入图片描述

源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJZwygeF-1677067561266)(RocketMQTemplate 实现消息发送.assets/image-20230216170539136.png)]

通过观看源码我们发现在封装RocketMQ消息时会将属性塞进消息头中,然后发送。在消费时监听器会从消息头中获取该属性过滤消息。

3. 同步消息

同步消息有返回值SendResult,等到消息发送成功后才算结束。

    /*** 同步消息有返回值SendResult,等到消息发送成功后才算结束。*/@Testpublic void sendSyncMsg() {SendResult result = rocketMQTemplate.syncSend("Demo:sync", "同步消息测试");System.out.println(JSONObject.toJSONString(result));}

源码

public SendResult syncSend(String destination, Object payload) {return syncSend(destination, payload, producer.getSendMsgTimeout());
}

在第一节中我们已经看过其源码,底层是调用了DefaultMQProducer的send方法~


4. 延时消息

/*** 延时消息*/
@Test
public void sendDelayMsg() {Message<String> msg = MessageBuilder.withPayload("延时消息测试").build();rocketMQTemplate.syncSend("Demo:delay", msg, 100, 3);
}

在RocketMQ中并不支持任意时间的延迟,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18:

// org/apache/rocketmq/store/config/MessageStoreConfig.java
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

源码

  • destination:topicName:tags,主题:标签,可单Topic不指定Tag
  • message:org.springframework.messaging.Message具有标题和正文的通用消息实体
  • timeout:消息发送时间域
  • delayLevel:延迟消息的级别

在这里插入图片描述

5. 批量消息

批量发送消息能显著提高传递小消息的性能。但需要注意这些批量消息应该有相同的topic,相同的waitStoreMsgOK,而且不能是延时消息。此外消息的大小也有限制~

  1. 消息体大小最大为 4MB, 一般建议发送的消息体在 4kb 之内 ( 性能最佳 )。

  2. 消息属性最大为 32kb,一般建议发送的消息属性在 1kb 之内 ( 性能最佳 )。

4MB 这个上限值不能修改,这个会影响全局性能。如果消息体的确很大,建 议侧优化消息体的内容,避免发送大消息或者带有链接地址的消息,或者可 以缩短或者分两条发送。

public <T extends Message> SendResult syncSend(String destination, Collection<T> messages) {return syncSend(destination, messages, producer.getSendMsgTimeout());
}

Demo

/*** 批量消息*/
@Test
public void sendOneMsg() {ArrayList<Message<String>> messages = new ArrayList<>();for (int i = 0; i < 10; i++) {messages.add(MessageBuilder.withPayload("批量消息"+(i+1)).build());}rocketMQTemplate.syncSend("Demo:batch", messages);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5RtQO05S-1677067621975)(RocketMQTemplate 实现消息发送.assets/image-20230216192416856.png)]

瞅瞅源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hsgBtIaO-1677067621976)(RocketMQTemplate 实现消息发送.assets/image-20230216193339428.png)]

6. 异步消息

异步消息无返回值,需要传入回调类。无需等待消息是否发送成功。

public void asyncSend(String destination, Object payload, SendCallback sendCallback) {asyncSend(destination, payload, sendCallback, producer.getSendMsgTimeout());
}

Demo

@Test
public void sendAsyncMsg() throws InterruptedException {rocketMQTemplate.asyncSend("Demo:async", "异步消息测试", new SendCallback() {@Overridepublic void onSuccess(SendResult sendResult) {System.out.println("异步消息发送成功");}@Overridepublic void onException(Throwable throwable) {System.out.println("异步消息发送失败");}});Thread.sleep(1000);
}

源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTUCRsaV-1677067655423)(RocketMQTemplate 实现消息发送.assets/image-20230215205325283.png)]

同理,最终调用的也是producer的send方法。

7. 单向消息

单向消息,与UDP类似,此方法在返回前不会等待代理的确认。显然,它具有最大的吞吐量,但也有消息丢失的可能性。

/*** 单向消息,与UDP类似,此方法在返回前不会等待代理的确认。显然,它具有最大的吞吐量,但也有消息丢失的可能性。*/
@Test
public void sendOneMsg() {rocketMQTemplate.sendOneWay("Demo:one", "单向消息测试");
}

源码

/*** Same to {@link #sendOneWay(String, Message)}** @param destination formats: `topicName:tags`* @param payload the Object to use as payload*/
public void sendOneWay(String destination, Object payload) {Message<?> message = MessageBuilder.withPayload(payload).build();sendOneWay(destination, message);
}

在这里插入图片描述

8. 顺序消息

大家有没有发现上面批量发送的消息被消费的时候顺序错乱了,有时只有保证消息的顺序消费才有意义。比如网购下单到付款时分别会发送生成订单、锁定库存、成功下单三个消息,消费时要按照这个顺序依次消费才有意义。

顺序错乱的原因

首先,我们先来分析一下顺序错乱的原因,其实RocketMQ里的分区队列MessageQueue本身是能保证FIFO的,正常情况下不能顺序消费消息主要有两个原因:

  1. Producer发送消息到MessageQueue时是轮询发送的,消息被发送到不同的分区队列,就不能保证FIFO了。
  2. Consumer默认是多线程并发消费同一个MessageQueue的,即使消息是顺序到达的,也不能保证消息顺序消费。

综上所述,RocketMQ要想实现顺序消息,核心就是Producer同步发送,确保一组顺序消息被发送到同一个分区队列,然后Consumer确保同一个队列只被一个线程消费。

RocketMQ的特性

顺序消息是RocketMQ的特性之一,它可以让Consumer消费消息的顺序严格按照消息的发送顺序来进行。顺序消息可以分为全局有序和分区有序,绝大部分场景下,分区有序就已经能够满足需求了。

  • 全局有序:某个Topic下所有的消息都是有序的,所有消息按照严格的先进先出的顺序进行生产和消费,要求Topic下只能有一个分区队列,且Consumer只能有一个线程消费,适用对性能要求不高的场景。
  • 分区有序:某个Topic下,所有消息根据ShardingKey进行分区,相同ShardingKey的消息必须被发送到同一个分区队列,因为队列本身是可以保证先进先出的,此时只要保证Consumer同一个队列单线程消费即可。

RocketMQTemplate提供三种发送顺序消息的方式:

  • syncSendOrderly():同步发送顺序消息
  • asyncSendOrderly():异步发送顺序消息
  • sendOneWayOrderly():单向发送顺序消息

源码解析

先了解一下相关的组建类

1、MessageQueueSelector

分区队列选择器,它是一个接口,只有一个select方法,根据ShardingKey从Topic下所有的分区队列中,选择一个目标队列进行消息发送,必须确保相同ShardingKey选择的是同一个分区队列,常见作法是对队列数取模。默认选择队列方式是计算 hashKey 的 hashCode值来选择队列。
在这里插入图片描述

Demo

首先消费者指定最大线程数为一,这样才能确保每个队列只能被一个线程消费
在这里插入图片描述
当我们在发消息时可以通过指定相同的ShardingKey达到多条消息按照发送顺序发送到相同的队列。

/*** 顺序消息*/
@Test
public void sendOrderMsg() {for (int i = 0; i < 10; i++) {rocketMQTemplate.syncSendOrderly("Demo:order", "同步发送顺序消息"+i, 0+"");}for (int i = 0; i < 10; i++) {rocketMQTemplate.asyncSendOrderly("Demo:order", "异步发送顺序消息" + i, 0 + "", new SendCallback() {@Overridepublic void onSuccess(SendResult sendResult) {return;}@Overridepublic void onException(Throwable e) {return;}});}for (int i = 0; i < 10; i++) {rocketMQTemplate.sendOneWayOrderly("Demo:order", "单向发送顺序消息" + i, 0 + "");}}

或者我们也可以重写MessageQueueSelector类的select()方法自定义选择队列的规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpqu6m5R-1677067748312)(RocketMQTemplate 实现消息发送.assets/image-20230217101616074.png)]

9. 事务消息

分布式消息选型的时候是否支持事务消息是一个很重要的考量点,而目前只有RocketMQ对事务消息支持的最好。

Apache RocketMQ在4.3.0版中已经支持分布式事务消息,这里RocketMQ采用了2PC的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息,如下图所示。
在这里插入图片描述

概要

RocketMQ实现事务消息主要分为两个阶段:正常事务的发送及提交、事务信息的补偿流程 整体流程为:

  1. 正常事务发送与提交阶段

    1. 生产者发送一个半消息给MQServer(半消息是指消费者暂时不能消费的消息)
    2. 服务端响应消息写入结果,半消息发送成功
    3. 开始执行本地事务
    4. 根据本地事务的执行状态执行Commit或者Rollback操作
  2. 事务信息的补偿流程(补偿阶段主要是用于解决生产者在发送Commit或者Rollback操作时发生超时或失败的情况。)

    1. 如果MQServer长时间没收到本地事务的执行状态会向生产者发起一个确认回查的操作请求
    2. 生产者收到确认回查请求后,检查本地事务的执行状态
    3. 根据检查后的结果执行Commit或者Rollback操作

RocketMQ是如何实现事务消息提交前消费者不可见呢?

事务消息相对普通消息最大的特点就是一阶段发送的消息对用户是不可见的,也就是说消费者不能直接消费。这里RocketMQ的实现方法是原消息的主题与消息消费队列,然后把主题改成RMQ_SYS_TRANS_HALF_TOPIC ,这样由于消费者没有订阅这个主题,所以不会被消费。

如何处理第二阶段的失败消息?

在本地事务执行完成后会向MQServer发送Commit或Rollback操作,此时如果在发送消息的时候生产者出故障了,那么要保证这条消息最终被消费,MQServer会像服务端发送回查请求,确认本地事务的执行状态。
当然了rocketmq并不会无休止的的信息事务状态回查,默认回查15次,如果15次回查还是无法得知事务状态,RocketMQ默认回滚该消息。

事务消息状态有哪几种?

TransactionStatus.CommitTransaction:提交事务消息,消费者可以消费此消息

TransactionStatus.RollbackTransaction:回滚事务,它代表该消息将被删除,不允许被消费。

TransactionStatus.Unknown :未知状态,它代表需要检查消息队列来确定状态。

Demo

首先编写一个Controller模拟发送10调事务消息,并且依次指定key为1~10。

/*** 发送事务消息测试*/
@GetMapping("/tx")
public void sendTransactionMsg() {for (int i = 1; i <= 10; i++) {// 发送指定事务id的消息Message msg = MessageBuilder.withPayload("事务消息" + i).setHeader(RocketMQHeaders.KEYS, i).build();TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("Demo:tx", msg, null);}
}

其次,编写一个事务监听器类实现RocketMQLocalTransactionListener的 “执行本地事务” 方法 和 “检查事务状态” 方法。当执行完本地事务方法后,消息的状态为UNKNOWN则会在指定次数下调用 “检查事务状态” 方法。

@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQTransactionListener
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {/*** 执行本地事务逻辑** @param msg* @param arg* @return*/@Overridepublic RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {// 模拟当key为偶数时提交事务,为基数UNKNOWN(在指定次数下检查当前事务状态)MessageHeaders headers = msg.getHeaders();//获取事务IDString transactionId = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);String key = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.KEYS);log.info("执行本地事务,事务id:{},key:{}", transactionId, key);if (Integer.parseInt(key) % 2 == 0) {//执行成功,可以提交事务return RocketMQLocalTransactionState.COMMIT;} else {return RocketMQLocalTransactionState.UNKNOWN;}}/*** 检查事务状态** @param msg* @return*/@Overridepublic RocketMQLocalTransactionState checkLocalTransaction(Message msg) {// 模拟检查事务状态时回滚MessageHeaders headers = msg.getHeaders();String transactionId = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);String key = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.KEYS);log.info("检查本地事务,事务id:{},key:{}", transactionId, key);return RocketMQLocalTransactionState.ROLLBACK;}
}

当我们调用发送事务消息接口时,发现每条消息都会执行本地事务。可以根据消费消息状况分析出事务消息根据我们所设定的key是偶数的情况下发送消息。
在这里插入图片描述
那么对于执行完本地事务后,消息状态为 UNKNOWN(未知)的消息则会在指定次数以及指定时间间隔下检查事务状态。
在这里插入图片描述

源码解读

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过源码分析可知,首先是向MqServe发送了事务消息并返回消息的状态。

  • 若消息发送成功为其生成事务id,并执行本地事务方法并返回事务消息状态。
  • 若消息发送失败则默认事务消息状态为回滚。

发送单向消息返回事务状态,MqServe根据消息的事务状态执行相关的事务操作。

  • 如果是 commit 会将消息投递到真实的 topic 中,然后再投递一个表示删除的消息到 RMS_SYS_TRANS_HALF_TOPIC 中,表示当前事务完成;
  • 如果是 rollback,则只需投递表示删除的消息即可
  • 如果是 TRANSACTION_NOT_TYPE,则一段时间后再次及检查,当检查的次数超过上限(默认15次),则丢弃消息

相关文章:

RocketMQTemplate 实现消息发送

代码托管于gitee&#xff1a;easy-rocketmq 文章目录一、前置工作二、消费者三、生产者1. 普通消息2. 过滤消息3. 同步消息4. 延时消息5. 批量消息6. 异步消息7. 单向消息8. 顺序消息9. 事务消息概要Demo源码解读一、前置工作 1、导入依赖 <dependency><groupId>…...

教师干货丨这5款微课必备提效神器,我要告诉全世界!

微课是一种短小精悍的视频教学形式&#xff0c;其设计和演示因特别简洁明了而被定义为“小而美”。由于只在几分钟时间内向学生传授所需知识&#xff0c;微课为学习者提供更多的选择机会和时间节约的便利&#xff0c;而这种趋势已经逐渐在新的社交媒体环境中显现出来。在制作微…...

timm使用swin-transformer

1.安装 pip install timm2.timm中有多少个预训练模型 #timm中有多少个预训练模型 model_pretrain_list timm.list_models(pretrainedTrue) print(len(model_pretrain_list), model_pretrain_list[:3])3加载swin模型一般准会出错 model_ft timm.create_model(swin_base_pat…...

【java基础】java八大基本数据类型和运算符

文章目录说明八大基本数据类型整型浮点型字符型布尔类型类型转换java运算符基础运算符二元运算符自增自减运算符关系和boolean运算符三元运算符位运算符运算符优先级说明 这里介绍java的八大基本数据类型和运算符 八大基本数据类型 java中有八大数据类型&#xff0c;4个整型…...

Mybatis源码学习笔记(四)之Mybatis执行增删改查方法的流程解析

1 Mybatis流程解析概述 Mybatis框架在执行增伤改的流程基本相同&#xff0c; 很简单&#xff0c;这个大家只要自己写个测试demo跟一下源码,基本就能明白是怎么回事&#xff0c;查询操作略有不同&#xff0c; 这里主要通过查询操作来解析一下整个框架的流程设计实现。 2 Mybat…...

浅谈测试用例设计

前言 最近干的最多的事情就是设计测试用例、评审测试用例了&#xff0c;于是我不禁又想到了一个经典的问题&#xff1a;如何设计出优秀的测试用例&#xff1f; 可能有些童鞋看到这个问题会有些不以为然&#xff0c;这有什么好想的&#xff1f;干个测试谁还不会设计测试用例&a…...

python 利用装饰器实现类似于flask路由

例子1&#xff1a; def f1():print(1111)def f2():print(2222)if __name__ __main__:print(33)打印结果&#xff1a; 33 在例子1中&#xff0c;f1() 与f2() 都没有被调用&#xff0c;只执行了print(33) f1与f2&#xff0c;是没有被调用的&#xff0c;但是如果f1 和 f2 上面…...

git 拉取远程分支到本地

目录&#xff1a;***&#xff01;本小作者&#xff0c;是将终端和Git的可视化插件结合使用&#xff0c;刚接触的可以自习看一下&#xff0c;内容简单&#xff0c;避免弯路&#xff01;***一&#xff0c;简单了解远程分支1&#xff0c;连接远程&#xff1a;2&#xff0c;提交&am…...

Answering Multi-Dimensional Range Queries under Local Differential Privacy

文章目录AbstractIntroduction2 PRELIMINARIES2.12.2 Categorical Frequency Oracles4 GRID APPROACHES4.1概述Abstract 在本文中&#xff0c;我们解决了在局部差异隐私下回答多维范围查询的问题。有三个关键的技术挑战&#xff1a;捕捉属性之间的相关性&#xff0c;避免维度的…...

手把手搭建springboot项目05-springboot整合Redis及其业务场景

目录前言一、食用步骤1.1 安装步骤1.1.1 客户端安装1.2 添加依赖1.3 修改配置1.4 项目使用1.5 序列化二、应用场景2.1 缓存2.2.分布式锁2.2.1 redis实现2.2.2 使用Redisson 作为分布式锁2.3 全局ID、计数器、限流2.4 购物车2.5 消息队列 (List)2.6 点赞、签到、打卡 (Set)2.7 筛…...

Flutter基础语法(六)var、final、const、late

Flutter基础 第六章 Flutter关键字var、final、const、late的区别与使用 文章目录Flutter基础前言一、var1.var是什么?2.var如何使用3.var自动推断类型4.var可以再次赋值5.var指定类型二、final1.final是什么?2.final声明但不赋值3.final赋值多次4.final正常使用三、const1.…...

Linux之安装node

Linux之安装node步骤如下 1.去网站下载node 下载地址&#xff1a; https://npm.taobao.org/mirrors/ 2.上传到指定目录下 3.解压 tar -zxvf node-v17.3.0-linux-x644.配置node环境变量 //执行以下命令 vim /etc/profile //在path中加入以下内容 /usr/local/node-v15.14.0/b…...

二叉树、二叉搜索树、二叉树的最近祖先、二叉树的层序遍历【零神基础精讲】

来源0x3f&#xff1a;https://space.bilibili.com/206214 文章目录二叉树[104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)[111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)[129. 求根节点到叶节点…...

【算法】【数组与矩阵模块】求最长可整合子数组和子数组的长度

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介绍 …...

数据结构:循环队列的实现(leetcode622.设计循环队列)

目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口 3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览 三.静态单向循环链表实现循环队列 1.链表循环队列的结构设计 2.创建静…...

[qiankun]实战问题汇总

[qiankun]实战问题汇总ERROR SyntaxError: Cannot use import statement outside a module问题分析解决方案子应用命名问题问题分析解决方案jsonpFunction详细错误信息问题分析解决方案微应用的注册问题Uncaught Error: application cli5-beta6-test-name died in status LOADI…...

Kafka(6):服务端常用参数配置

参数配置&#xff1a;config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership.…...

2023爱分析·云原生智能运维中台市场厂商评估报告:秒云(miaoyun.io)

目录 1. 研究范围定义 2. 云原生智能运维中台市场定义 3. 厂商评估&#xff1a;秒云&#xff08;miaoyun.io&#xff09; 4. 入选证书 1. 研究范围定义 数字化时代&#xff0c;应用成为企业开展各项业务的落脚点。随着业务的快速发展&#xff0c;应用的功能迭代变得越…...

hadoop容器化部署

1、原容器 java:openjdk-8u111-jre jre路径&#xff1a; /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/java-1.8.0-openjdk-amd64 2、安装ssh docker run -it --name hadoop-test java:openjdk-8u111-jre bash apt-get update apt-get install openssh service ssh start …...

【07-JVM面试专题-JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态链接吧?】

JVM运行时数据区的虚拟机栈你知道吗&#xff1f;它的基本结构是什么呢&#xff1f;你知道栈帧的结构吗&#xff1f;那你说说动态链接吧&#xff1f; JVM运行时数据区的虚拟机栈你知道吗&#xff1f;它的基本结构是什么呢&#xff1f;你知道栈帧的结构吗&#xff1f;那你说说动态…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

13.10 LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析

LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析 LanguageMentor 对话式训练系统架构与实现 关键词:多轮对话系统设计、场景化提示工程、情感识别优化、LangGraph 状态管理、Ollama 私有化部署 1. 对话训练系统技术架构 采用四层架构实现高扩展性的对话训练…...