谷粒商城のRabbitMQ基础篇

文章目录

  • 前言
  • 一、Rabbit MQ简介
    • 1、基本概念
    • 2、组件架构
  • 二、使用步骤
    • 1.引入依赖
    • 2.application.properties
    • 3、docker 安装Rabbit MQ
    • 3、使用案例
      • 3.1、定义队列
      • 3.2、定义交换机
      • 3.3、绑定
      • 3.4、发送消息
      • 3.5、接受消息
      • 3.5、自定义消息序列化方式
      • 3.6、演示Fanout 交换机模式
      • 3.7、演示Topic 交换机模式
  • 三、消息可靠性
    • 3.1、ConfirmCallback&ReturnCallback
    • 3.2、设置手动ACK
      • 3.2.1、演示自动签收消息丢失
      • 3.2.2、演示手动签收
  • 总结


前言

  本篇主要介绍消息中间件Rabbit MQ的基本概念及使用,以及保证消息的可靠投递
  对应视频p248-p261


一、Rabbit MQ简介

1、基本概念

  Rabbit MQ是一个消息代理 - 一个消息系统的媒介。它可以为你的应用提供一个通用的消息发送和接收平台,并且保证消息在传输过程中的安全。这是官方文档给予Rabbit MQ的定义。
  Rabbit MQ是基于AMQP 模型,AMQP(高级消息队列协议)是一个网络协议。它支持符合要求的客户端应用(application)和消息中间件代理(messaging middleware broker)之间进行通信。和JMS(Java Message Service)JAVA消息服务最大的区别在于,AMQP具有跨平台,跨语言的特性,并且支持更多的消息模型,并且简化了消息的类型(网络通信统一转换为流)。
  在企业级开发中运用Rabbit MQ,主要是为了达到异步削峰解耦的目的:

  • 异步:假设用户注册完成后需要发送短信和邮件,如果是同步模式,就需要注册->发送短信->发送邮件顺序执行。假设某一个步骤调用第三方的接口执行的时间较长,会极大地拖延整个业务流程的完成时间,需要等到最后一步执行完成后再返回结果,这样对于用户是非常不友好的。而引入Rabbit MQ,可以做到注册完成后直接返回结果给用户,异步通知其他的服务发送短信,发送邮件。
  • 削峰:对于一些电商平台,在双11,618等活动时,用户请求会达到峰值,服务器一般短时间内无法承受这样的负担,通过Rabbit MQ,可以将用户的请求暂时存放入队列中,然后负责业务处理的模块按照一定的规则从队列中获取请求进行处理,也就是起到一个缓冲的作用。
  • 解耦:假设现在有三个系统,B,C系统需要接受A系统的通知,如果后续又加入了一个D系统,那么A系统还需要编写针对D系统发送通知的接口。引入Rabbit MQ,A系统可以将通知发送到队列,需要接受消息的系统自行监听队列即可。

2、组件架构

  Rabbit MQ的基本架构,包括生产者消费者消息交换机队列通道虚拟主机

  • 生产者 是消息的生产方,负责编辑消息发送到交换机。
  • 消费者 是消息的消费方,负责监听队列,从队列中获取消息并处理。
  • 交换机 作为消息和队列的中间组件,消息需要经过交换机,而不是直接发送至队列。
  • 队列 用来保存消息直到发送给消费者。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
  • 通道信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。可以复用一条TCP连接。虽然客户端和 RabbitMQ 服务器之间只有一个 TCP 连接,但可以通过多个信道并行处理不同的消息通信任务。每个信道在逻辑上是独立的,它们互不干扰。在 RabbitMQ 中,客户端首先与服务器建立一个 TCP 连接,然后通过该连接创建多个信道来进行通信。
  • 虚拟主机 上述的交换机,队列,通道都是运行在虚拟主机上的。可以将虚拟主机理解成一个命名空间,允许你在同一个 RabbitMQ 实例中分隔不同的应用或项目。不同的队列、交换机等资源可以在不同的虚拟主机中拥有相同的名称,而不会产生冲突。并且每个虚拟主机都有一套独立的权限管理。

二、使用步骤

1.引入依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>

2.application.properties

spring.rabbitmq.host=自己的地址
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

  还需要在启动类上加入@EnableRabbit注解

3、docker 安装Rabbit MQ

docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p
25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management

3、使用案例

  同样的Rabbit MQ提供了两个模版:AmqpAdminRabbitTemplateAmqpAdmin 可用于队列,交换机,绑定关系的定义。RabbitTemplate可以用于发送消息。

3.1、定义队列

	 /*** 创建队列*/@Testpublic void createQueue() {//参数二控制是否持久化amqpAdmin.declareQueue(new Queue("hello-java-queue", true, false, false,null));System.out.println("queue created");}

3.2、定义交换机

  常见的交换机有:

  • Direct 交换机 根据精确匹配的路由键来将消息路由到特定队列。
  • Fanout 交换机 将消息广播到所有绑定的队列,无需考虑路由键。
  • Topic 交换机 根据模式匹配的路由键,将消息路由到匹配的队列。
  • Headers 交换机 根据消息头中的属性值匹配,而非路由键。

  前三种模式最为常用,Topic 交换机模式匹配 也称为通配符模式,一般有两种,#匹配0个或多个单词,*匹配一
个单词。

	 /*** 创建交换机(直连模式)*/@Testpublic void createExchange() {//参数二控制是否持久化amqpAdmin.declareExchange(new DirectExchange("hello-java-exchange", true, false,null));System.out.println("exchange created");}

3.3、绑定

 	 /*** 将队列绑定到交换机上*/@Testpublic void createBinding() {//参数一 队列名 参数二:绑定类型 参数三:交换机名 参数四:路由键amqpAdmin.declareBinding(new Binding("hello-java-queue",Binding.DestinationType.QUEUE,"hello-java-exchange","hello.java",null));System.out.println("binding created");}

3.4、发送消息

  发送的消息通过路由键找到对应的交换机。

    /*** 发送消息*/@Testpublic void sendMessage() {//参数一:交换机名 参数二:路由键rabbitTemplate.convertAndSend("hello-java-exchange","hello.java","这是一个测试信息");}

3.5、接受消息

  需要在方法上加入@RabbitListener注解,指定监听的队列。

	 @RabbitListener(queues = "hello-java-queue")public void listenMessage(Message message, Channel channel) {}

3.5、自定义消息序列化方式

@Configuration
public class MyRabbitConfig {@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}}

3.6、演示Fanout 交换机模式

    /*** 创建交换机(广播模式)*/@Testpublic void createFanoutExchange() {amqpAdmin.declareExchange(new FanoutExchange("hello-java-fanout-exchange", true, false,null));}@Testpublic void createQueue2() {amqpAdmin.declareQueue(new Queue("hello-java-fanout-queue", true, false, false,null));}/*** 将队列绑定到交换机上*/@Testpublic void createBindingFanout() {amqpAdmin.declareBinding(new Binding("hello-java-queue",Binding.DestinationType.QUEUE,"hello-java-fanout-exchange","hello.java",null));amqpAdmin.declareBinding(new Binding("hello-java-fanout-queue",Binding.DestinationType.QUEUE,"hello-java-fanout-exchange","hello.java",null));System.out.println("binding created");}/*** 发送消息*/@Testpublic void sendMessage() {rabbitTemplate.convertAndSend("hello-java-fanout-exchange","hello.js","这是一个测试信息");}@RabbitListener(queues = {"hello-java-queue","hello-java-fanout-queue"})public void receiveQueue(String message) {System.out.println(message);}

  广播模式下,在发送消息时,即使指定的路由键和队列绑定在交换机上的不同,监听相关队列的消费者也可以接收到消息。即:fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。
在这里插入图片描述

3.7、演示Topic 交换机模式

    /*** 创建交换机(通配符模式)*/@Testpublic void createExchangeTopic() {amqpAdmin.declareExchange(new TopicExchange("hello-java-topic-exchange", true, false,null));System.out.println("exchange created");}/*** 创建通配符队列1*/@Testpublic void createTopicQueue1() {amqpAdmin.declareQueue(new Queue("hello-java-topic-queue1", true, false, false,null));}/*** 创建通配符队列2*/@Testpublic void createTopicQueue2() {amqpAdmin.declareQueue(new Queue("hello-java-topic-queue2", true, false, false,null));}/*** 将队列绑定到交换机上(通配符模式)*/@Testpublic void createBindingTopic() {amqpAdmin.declareBinding(new Binding("hello-java-topic-queue1",Binding.DestinationType.QUEUE,"hello-java-topic-exchange","#.java",null));amqpAdmin.declareBinding(new Binding("hello-java-topic-queue2",Binding.DestinationType.QUEUE,"hello-java-topic-exchange","*.java",null));System.out.println("binding created");}@GetMapping("/send")public void sendMessage() {rabbitTemplate.convertAndSend("hello-java-topic-exchange", "java", "这是一个测试信息");rabbitTemplate.convertAndSend("hello-java-topic-exchange", "hello.world.java", "这是一个测试信息");}/*** 监听通配符队列1 和交换机绑定的路由键是 #.java* @param message* @param channel*/@RabbitListener(queues = "hello-java-topic-queue1")public void receiveTopicQueue(String message,Channel channel) {System.out.println("监听hello-java-topic-queue1的消息是" + message);}

  首先向通配符模式的交换机发送了两个消息,消费者选择监听与交换机绑定了#.java路由键的队列hello-java-topic-queue1,由于发送的消息javahello.world.java#通配符能匹配上(前者匹配0个,后者匹配2个),所以两条消息消费者都接受到了。
在这里插入图片描述
  接下来测试*通配符,由于*通配符只能匹配单个单词,所以只监听到了hello.java

    @GetMapping("/send")public void sendMessage() {rabbitTemplate.convertAndSend("hello-java-topic-exchange", "java", "这是一个测试信息java");rabbitTemplate.convertAndSend("hello-java-topic-exchange", "hello.world.java", "这是一个测试信息hello.world.java");rabbitTemplate.convertAndSend("hello-java-topic-exchange", "hello.java", "这是一个测试信息hello.java");}/*** 监听通配符队列2 和交换机绑定的路由键是 *.java* @param message* @param channel*/@RabbitListener(queues = "hello-java-topic-queue2")public void receiveTopicQueue(String message,Channel channel) {System.out.println("监听hello-java-topic-queue2的消息是" + message);}


三、消息可靠性

  在Rabbit MQ中,消息首先需要发送到交换机,再由交换机发送到队列,最后消费者从队列中读取消息。中转的步骤较多,其中每一步都有可能发生消息丢失的问题。Rabbit MQ采用消息投递回调消息确认机制分别保证生产者方和消费者方的消息可靠性。

3.1、ConfirmCallback&ReturnCallback

  ConfirmCallback是消息发送到交换机的回调,无论成功或者失败都会触发。ReturnCallback是消息从交换机到队列的回调,只有失败了才会触发。
  在使用之前,需要在配置文件中加上:

spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true

  可以在自定义配置类中为RabbitTemplate加上对应的配置:

    /*** 消息发送到交换机的回调 ConfirmCallback(成功和失败都会触发)* 从交换机到队列投递失败的回调ReturnCallback* 从队列到消费者是 ack机制 只要消费者没有手动ack,消息就默认未被消费,是unacked状态,服务器宕机,消息会重置为ready状态*/@PostConstructpublic void init() {rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {/*** Confirmation callback.** @param correlationData correlation data for the callback.* @param ack             true for ack, false for nack* @param cause           An optional cause, for nack, when available, otherwise null.*/@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {System.out.println("触发ConfirmCallback:correlationData:"+correlationData+",ack:"+ack+",cause:"+cause);}});rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {/*** Returned message callback.** @param message    the returned message.* @param replyCode  the reply code.* @param replyText  the reply text.* @param exchange   the exchange.* @param routingKey the routing key.*/@Overridepublic void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {System.out.println("触发ReturnCallback:message"+message+"replyCode:"+replyCode+",exchange:"+exchange+",routingKey:"+routingKey);}});}

3.2、设置手动ACK

  如果没有进行任何设置,在Rabbit MQ中默认消息都是自动签收的:

3.2.1、演示自动签收消息丢失

    @GetMapping("/send")public void sendMessage() {for (int i = 0; i < 5; i++) {rabbitTemplate.convertAndSend("hello-java-exchange","hello.java","这是一个测试信息"+i);}}@RabbitListener(queues = "hello-java-queue")public void listenMessage(Message message, Channel channel) {System.out.println("listenMessage接收到的消息" + message);throw new NullPointerException();}

在这里插入图片描述
  上图的1条消息已经被自动签收
在这里插入图片描述
  模拟出现异常,消息不会丢失。在这里插入图片描述在这里插入图片描述
  假设此时服务器宕机了,队列中剩下未处理的消息会丢失:

    /*** 同一个消息只能被一个监听者接受* 一个消息处理完成后,才能处理下一个消息* @param message* @param channel*/@RabbitListener(queues = "hello-java-queue")public void listenMessage(Message message, Channel channel) {System.out.println("listenMessage接收到的消息" + message);}

  通过jps -l找到当前服务进程,并Stop-Process -Id 25364 -Force强行终止:

在这里插入图片描述在这里插入图片描述  发现剩下的消息全部丢失:

在这里插入图片描述

3.2.2、演示手动签收

  我们可以设置消息手动确认,在配置文件中加入:spring.rabbitmq.listener.simple.acknowledge-mode=manual,打上断点:
在这里插入图片描述  队列中有5条unack(未确认)的消息。
在这里插入图片描述  接下来处理了两个消息,但是没有手动确认:
在这里插入图片描述  可以看到在控制台中依旧是5条unack状态:
在这里插入图片描述  假设此时服务器宕机了:
在这里插入图片描述  可以看到控制台中这5条消息回到了ready状态,没有丢失:
在这里插入图片描述  如果需要手动签收,需要在消费者方监听的代码中,使用channelbasicAckbasicNack方法,前者是签收,后者是拒绝,其中拒绝又有两种模式,一种是重新放回队列,另一种是丢弃:

  • 拒绝并丢弃
    @RabbitListener(queues = "hello-java-queue")public void listenMessage(Message message, Channel channel) {System.out.println("监听hello-java-queue的消息是"+message);long deliveryTag = message.getMessageProperties().getDeliveryTag();try {//手动确认if (deliveryTag % 2 == 0) {//签收channel.basicAck(deliveryTag, false);System.out.println("接收到的消息" + deliveryTag);} else {//拒绝(丢弃)channel.basicNack(deliveryTag, false, false);System.out.println("拒绝了消息" + deliveryTag);}} catch (IOException e) {throw new RuntimeException(e);}}

  重新启动项目,消息一部分被拒绝,一部分被签收并消费
在这里插入图片描述  队列清空
在这里插入图片描述

  • 拒绝并重新放回队列:当一个消息被拒绝又重新放回队列时,会被再次消费,创建两个消费者监听hello-java-queue
    @RabbitListener(queues = "hello-java-queue")public void listenMessage(Message message, Channel channel) {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {//手动确认if (deliveryTag % 2 == 0) {//签收channel.basicAck(deliveryTag, false);System.out.println("listenMessage接收到的消息" + deliveryTag);} else {//拒绝channel.basicNack(deliveryTag, false, true);System.out.println("listenMessage拒绝了消息" + deliveryTag);}} catch (IOException e) {throw new RuntimeException(e);}}@RabbitListener(queues = {"hello-java-queue","hello-java-fanout-queue"})public void receiveQueue(Message message,Channel channel) {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {channel.basicAck(deliveryTag, false);System.out.println("receiveQueue接收到的消息"+deliveryTag);} catch (IOException e) {throw new RuntimeException(e);}}

  拒绝的消息可以放回队列被再次消费,直到有消费者签收为止。
在这里插入图片描述

总结

  下面总结一下Rabbit MQ 的工作流程

  1. 生产者与虚拟主机建立连接,经过信道,发送消息到交换机(带有路由键)。
  2. 交换机根据绑定和路由规则,将消息路由到一个或多个队列。
  3. 队列存储消息,等待消费者处理。
  4. 消费者从队列中接收消息,并处理。
  5. 消费者处理消息后,发送 ACK 确认,RabbitMQ 从队列中删除该消息。
  6. 如果消费者拒绝消息或处理失败,RabbitMQ 可能会将消息重新投递,或者发送到死信队列。

  其他诸如死信队列,延迟队列,消息幂等性,消息积压等将在高级篇中讲解。
  下一篇:订单服务&分布式事务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1556089.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Vue基础(二)

计算属性与监视姓名案例 插值语法实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>姓名案例&l…

用人工智能写作:专业作家利用 ChatGPT 的五种方式 ✍️

用人工智能写作&#xff1a;专业作家利用 ChatGPT 的五种方式 &#x1f3a8;✍️ 在写作领域&#xff0c;人工智能工具如 ChatGPT 正逐渐成为作家们的得力助手。它不仅帮助优化文本&#xff0c;还能激发灵感、完善叙事结构&#xff0c;甚至推动创新。本文将通过五个具体案例&a…

【微服务】服务注册与发现 - Eureka(day3)

CAP理论 P是分区容错性。简单来说&#xff0c;分区容错性表示分布式服务中一个节点挂掉了&#xff0c;并不影响其他节点对外提供服务。也就是一台服务器出错了&#xff0c;仍然可以对外进行响应&#xff0c;不会因为某一台服务器出错而导致所有的请求都无法响应。综上所述&…

实验4 循环结构

1、判断素数 【问题描述】从键盘输入一个大于1的正整数&#xff0c;判断是否为素数 【输入形式】输入一个正整数 【输出形式】输出该数是否为素数 【样例输入】10 【样例输出】10 is not a prime number 【样例说明】样例2 输入&#xff1a;-10 输出&#xff1a;error! #de…

jmeter学习(7)beanshell

beanshell preprocessor 发送请求前执行 beanshell postprocessor 发送请求前执行 获取请求相关信息 String body sampler.getArguments().getArgument(0).getValue(); String url sampler.getPath(); 获取响应报文 String responseprev.getResponseDataAsString(); 获…

北京自闭症寄宿学校大盘点:优质教育资源汇总

北京自闭症寄宿学校大盘点&#xff1a;优质教育资源中的璀璨明珠——兼谈广州星贝育园 在北京&#xff0c;随着社会对自闭症儿童教育的日益重视&#xff0c;越来越多的优质寄宿学校应运而生&#xff0c;为这些特殊的孩子提供了专业的康复与教育环境。然而&#xff0c;当我们把…

【数据结构】【链表代码】随机链表的复制

/*** Definition for a Node.* struct Node {* int val;* struct Node *next;* struct Node *random;* };*/typedef struct Node Node; struct Node* copyRandomList(struct Node* head) {if(headNULL)return NULL;//1.拷贝结点&#xff0c;连接到原结点的后面Node…

猫头虎深度解读:过去2周,AI领域的十大突破事件与未来展望

猫头虎深度解读&#xff1a;过去2周&#xff0c;AI领域的十大突破事件与未来展望 &#x1f680;&#x1f916; 大家好&#xff0c;我是猫头虎技术团队的代表&#xff01;这两周&#xff0c;人工智能领域再次掀起了技术与应用的新浪潮。从立法到技术进展&#xff0c;再到前沿应…

初始爬虫12(反爬与反反爬)

学到这里&#xff0c;已经可以开始实战项目了&#xff0c;多去爬虫&#xff0c;了解熟悉反爬&#xff0c;然后自己总结出一套方法怎么做。 1.服务器反爬的原因 服务器反爬的原因 总结&#xff1a; 1.爬虫占总PV较高&#xff0c;浪费资源 2.资源被批量抓走&#xff0c;丧失竞争力…

交叉熵的数学推导和手撕代码

交叉熵的数学推导和手撕代码 数学推导手撕代码 数学推导 手撕代码 import torch import torch.nn.functional as F# 二元交叉熵损失函数 def binary_cross_entropy(predictions, targets):# predictions应为sigmoid函数的输出&#xff0c;即概率值# targets应为0或1的二进制标…

MathType软件7.7最新版本下载安装教程+使用深度评测

嘿&#xff0c;各位亲爱的朋友们&#xff01;&#x1f44b; 今天我要来给大家安利一个神器——MathType软件&#xff01;&#x1f389; 如果你是一位学生、老师或者需要经常和数学公式打交道的科研工作者&#xff0c;那这个软件绝对是你的不二选择&#xff01;&#x1f60e; M…

ctf.bugku-备份是个好习惯

访问页面得到字符串 这串字符串是重复的&#xff1b; d41d8cd98f00b204e9800998ecf8427e 从前端、源码上看&#xff0c;除了这段字符串&#xff0c;没有其他信息&#xff1b;尝试解密&#xff0c;长度32位&#xff1b;各种解密方式试试&#xff1b; MD5免费在线解密破解_MD5在…

市面上8款AI论文大纲一键生成文献的软件推荐

在当前的学术研究和写作领域&#xff0c;AI论文大纲自动生成软件已经成为提高写作效率和质量的重要工具。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。本文将分享市面上8款AI论文大纲一键生成文献的软件&#xff0c;并特别推…

[git] github管理项目之环境依赖管理

导出依赖到 requirements.txt pip install pipreqs pipreqs . --encodingutf8 --force但是直接使用pip安装不了torch&#xff0c;需要添加源&#xff01;&#xff01; pip install -r requirements.txt -f https://download.pytorch.org/whl/torch_stable.htmlpython 项目中 …

Stable Diffusion绘画 | AI 图片智能扩充,超越PS扩图的AI扩图功能(附安装包)

来到「文生图」页面&#xff0c;输入固定的起手式提示词。 第1步&#xff0c;开启 ControlNet&#xff0c;将需要扩充的图片加载进来&#xff1a; 控制类型选择「Inpaint」&#xff0c;预处理器选择「inpaint_onlylama」&#xff0c;缩放模式选择「缩放后填充空白」&#xff1…

【数据结构】【链表代码】移除链表元素

移除链表元素 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val) { // 创建一个虚拟头节点&#xff0c;以处理头节点可能被删除的情况 struct…

代码随想录Day54

今天是国庆假期后的恢复做题的第一天&#xff0c;摆了那么久感觉还是有点没摆够哈哈哈哈&#xff01;今天两道题都是困难题&#xff0c;两道题都去看讲解了&#xff0c;感觉这两道题是高度相似的&#xff0c;接雨水用单调递增栈来做&#xff0c;柱状图中最大的矩形用单调递减栈…

tcp/ip、以太网、mqtt、modbus/tcp复习

1.osi参考模型 2. modbus是应用层报文传输协议&#xff0c;没有规定物理层&#xff0c;只规定了协议帧&#xff0c;但是定义了控制器能够认识和使用的消息结构&#xff0c;不管它们是经过何种网络进行通信的&#xff0c;具有很强的适应性。 一主多从&#xff0c;同一时间主机…

【动态规划-最长公共子序列(LCS)】力扣1035. 不相交的线

在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足&#xff1a; nums1[i] nums2[j] 且绘制的直线不与任何其他连线&#xff08;非水平线&#xff09…

Rethinking Graph Neural Networksfor Anomaly Detection

AAAI24 推荐指数 #paper/⭐⭐ (由于这个领域初读&#xff0c;因此给的推荐分可能不好) 个人总结&#xff1a; 其在半监督&#xff08;1%&#xff0c;40%&#xff09;的情况下&#xff0c;使用多通滤波器&#xff0c;将不同滤波器得到的特征拼接起来&#xff0c;来做分类&…