微服务—RabbitMQ

目录

初识MQ

同步和异步通讯

同步通讯的优缺点

异步调用方案

异步通信优缺点

常见MQ技术对比 

RabbitMQ快速入门 

安装RabbitMQ

RabbitMQ整体架构与相关概念 

常见消息模型​编辑

入门案例

SpringAMQP

基本介绍

SpringAMQP案例——模拟HelloWorld消息模型

SpringAMQP案例——模拟WorkQueue消息模型

SpringAMQP案例——模拟发布订阅消息模型

发布订阅消息模型介绍

案例——FanoutExchange

案例——DirectExchange

案例——TopicExchange

消息转换器


初识MQ

同步和异步通讯

        微服务间通讯有同步和异步两种方式:同步通讯就像打电话,需要实时响应,异步通讯就像发邮件,不需要马上回复。两种方式各有优劣,打电话可以立即得到响应,但是你却不能跟多个人同时通话。发送邮件可以同时与多个人收发邮件,但是往往响应会有延迟。


同步通讯的优缺点

优点:
时效性较强,可以立即得到结果。
缺点:
1. 耦合度高:每次加入新的需求,都要修改原来的代码;
2. 性能下降:调用者需要等待服务提供者响应,如果调用链过长则响应时间等于每次调用的时间之和;
3. 资源浪费:调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下会极度浪费系统资源;
4. 级联失败:如果服务提供者出现问题,所有调用方都会跟着出问题如同多米诺骨牌一样,迅速导致整个微服务群故障。


异步调用方案

        我们以购买商品为例,用户支付后需要调用订单服务完成订单状态修改,调用物流服务,从仓库分配响应的库存并准备发货。
        在事件模式中,支付服务是事件发布者,在支付完成后只需要发布一个支付成功的事件,事件中带上订单id。
        订单服务和物流服务是事件订阅者,订阅支付成功的事件,监听到事件后完成自己业务即可。
        为了解除事件发布者与订阅者之间的耦合,两者并不是直接通信,而是有一个中间Broker。发布者发布事件到Broker,不关心谁来订阅事件。订阅者从Broker订阅事件,不关心谁发来的消息。


异步通信优缺点

优点:
1. 吞吐量提升:无需等待订阅者处理完成,响应更快速;
2. 故障隔离:服务没有直接调用,不存在级联失败问题;
3. 调用间没有阻塞,不会造成无效的资源占用;
4. 耦合度极低,每个服务都可以灵活插拔,可替换;
5. 流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件。
缺点:
1. 架构复杂了,业务没有明显的流程线,不好管理;
2. 需要依赖于Broker的可靠、安全、性能。


常见MQ技术对比 


RabbitMQ快速入门 

安装RabbitMQ

步骤1 在线拉取镜像

​​​​​​​docker pull rabbitmq:3-management

步骤2 执行下面的命令来运行MQ容器,在命令行中设置用户名和密码

docker run \-e RABBITMQ_DEFAULT_USER=root \-e RABBITMQ_DEFAULT_PASS=123456 \--name mq \--hostname mq1 \-p 15672:15672 \-p 5672:5672 \-d \rabbitmq:3-management

步骤3 进入RabbitMQ管理平台

        安装好后,安装好后通过IP+端口访问管理界面。管理界面端口是15672,tcp连接的端口是5672。在浏览器中访问192.168.237.128:1567进入RabbitMQ管理平台,其中192.168.237.128为虚拟机ip地址。


RabbitMQ整体架构与相关概念 

RabbitMQ架构图

RabbitMQ中的几个概念
channel:操作MQ的工具
exchange:路由消息到队列中
queue:缓存消息
virtualhost:虚拟主机,是对queue、exchange等资源的逻辑分组 


常见消息模型


入门案例

发布者发送消息代码:

public class PublisherTest {@Testpublic void testSendMessage() throws IOException, TimeoutException {// 1.建立连接ConnectionFactory factory = new ConnectionFactory();// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码factory.setHost("192.168.150.101");factory.setPort(5672);factory.setVirtualHost("/");factory.setUsername("itcast");factory.setPassword("123321");// 1.2.建立连接Connection connection = factory.newConnection();// 2.创建通道ChannelChannel channel = connection.createChannel();// 3.创建队列String queueName = "simple.queue";channel.queueDeclare(queueName, false, false, false, null);// 4.发送消息String message = "hello, rabbitmq!";channel.basicPublish("", queueName, null, message.getBytes());System.out.println("发送消息成功:【" + message + "】");// 5.关闭通道和连接channel.close();connection.close();}
}

运行之后可以在RabbitMQ管理平台看到队列里已经有一个消息

点击该消息,通过Get Message可以查看接收到的消息内容

 消费者建立连接代码:

public class ConsumerTest {@Testpublic static void main(String[] args) throws IOException, TimeoutException {// 1.建立连接ConnectionFactory factory = new ConnectionFactory();// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码factory.setHost("192.168.237.128");factory.setPort(5672);factory.setVirtualHost("/");factory.setUsername("root");factory.setPassword("123456");// 1.2.建立连接Connection connection = factory.newConnection();// 2.创建通道ChannelChannel channel = connection.createChannel();// 3.创建队列String queueName = "simple.queue";channel.queueDeclare(queueName, false, false, false, null);// 4.订阅消息channel.basicConsume(queueName, true, new DefaultConsumer(channel){@Overridepublic void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties, byte[] body) throws IOException {// 5.处理消息String message = new String(body);System.out.println("接收到消息:【" + message + "】");}});System.out.println("等待接收消息。。。。");}
}

运行之后可以在RabbitMQ管理平台发现已经建立起一个连接,并且能够在idea控制台观察到从消息队列里获取的消息。

​​​​​​​

小结:

发布者和生产者的代码中,都有创建队列这一部分,是否会产生冲突?
由于无法确定发布者和生产者运行的前后顺序,为避免寻找不到所需绑定的队列,因此都需要创建队列,如果该队列已经存在,也不会产生冲突。

基本消息队列的消息发送流程
1.建connection
2.创建channel
3.利用channel声明队列
4.利用channel向队列发送消息

基本消息队列的消息接收流程
1.建connection
2.创建channel
3.利用channel声明队列
4.定义consumer的消费行为handleDelivery05.利用channel将消费者与队列绑定


SpringAMQP

基本介绍

AMQP(Advanced Message Queuing Protocol)是用于在应用程序或之间传递业务消息的开放标准。该协议与语言和平台无关,更符合微服务中独立性的要求。

Spring AMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息。包含两部分,其中spring-amqp是基础抽象spring-rabbit是底层的默认实现。


SpringAMQP案例——模拟HelloWorld消息模型

模拟消息发送:

步骤1. 在工程中引入AMQP依赖

<!--AMQP依赖,包含RabbitMQ-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

步骤2. 配置MQ地址:在publisher服务的application.yml中添加配置

spring:rabbitmq:host: 192.168.237.128 # rabbitMQ的ip地址port: 5672 # 端口username: rootpassword: 123456virtual-host: /

步骤3. 在publisher服务中设置测试类,利用convertAndSend方法实现信息发送

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAmqpTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void testSendMessage2SimpleQueue() {String queueName = "simple.queue";String message = "hello,spring amqp";rabbitTemplate.convertAndSend(queueName,message);}
}

运行之后可以看到消息队列中存在一条消息,消息内容为我们发送的内容


模拟消息接收:

步骤1. 在工程中引入AMQP依赖

<!--AMQP依赖,包含RabbitMQ-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

步骤2. 配置MQ地址:在consumer服务的application.yml中添加配置

spring:rabbitmq:host: 192.168.237.128 # rabbitMQ的ip地址port: 5672 # 端口username: rootpassword: 123456virtual-host: /

步骤2. 在consumer服务中新建一个类,编写消费逻辑

@Component
public class SpringRabbitListener {@RabbitListener(queues = "simple.queue")public void listenSimpleQueue(String msg){System.out.println("消费者接收到simple.queue的消息:【" + msg + "】");}
}

运行之后,通过idea控制台可以看到已经成功接收到消息

注意:消息一旦消费就会从队列删除,RabbitMQ没有消息回溯功能。


SpringAMQP案例——模拟WorkQueue消息模型

根据WorkQueue消息模型,有一个发布者和两个消费者,因此我们模拟消费者发送大量消息的情况。

/*** workQueue* 向队列中不停发送消息,模拟消息堆积。*/
@Test
public void testWorkQueue() throws InterruptedException {// 队列名称String queueName = "simple.queue";// 消息String message = "hello, message_";for (int i = 0; i < 50; i++) {// 发送消息rabbitTemplate.convertAndSend(queueName, message + i);Thread.sleep(20);}
}

再设置两个消费者,通过设置sleep休眠,明显区分两个消费者的性能。

@RabbitListener(queues = "simple.queue")
public void listenSimpleQueue1(String msg) throws InterruptedException {System.out.println("消费者1接收到的消息:【" + msg + "】" + LocalTime.now());Thread.sleep(20);
}@RabbitListener(queues = "simple.queue")
public void listenSimpleQueue2(String msg) throws InterruptedException {System.err.println("消费者2接收到的消息:【" + msg + "】" + LocalTime.now());Thread.sleep(200);
}

先运行发布者,发布50条消息,再运行消费者,控制台信息如下:

        通过观察控制台信息,我们可以发现,消费者1只接收单数的消息,而消费者2只接收双数的消息。当消费者1很快完成了自己的25条消息,消费者2却在缓慢的处理自己的25条消息。

        这是由WorkQueue消息模型中的消息预取机制所导致的。在该机制下,消费者无论当前是否能够处理消息,都会提前从队列中取出消息。因此,所有的消息会被平均分配给两个消费者。结果是,无论哪个消费者的接收速度较快,整体的消息接收速度都取决于接收速度较慢的消费者。

        为了解决这个问题,我们可以通过设置消费者每次获取消息的数量来进行限制。只允许每个消费者一次获取一条消息,并且要求在当前消息处理完毕之后才能获取下一条消息。通过这种方式,我们可以实现能者多劳的效果。

经过设置后,我们再次运行程序,可以发现结果不再像之前一样,消费者1能够根据自己的性能接收更多消息。

​​​​​​​


SpringAMQP案例——模拟发布订阅消息模型

发布订阅消息模型介绍

可以看到,在订阅模型中,多了一个exchange角色,而且过程略有变化:

Publisher:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)

  • Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有以下3种类型:

    • Fanout:广播,将消息交给所有绑定到交换机的队列

    • Direct:定向,把消息交给符合指定routing key 的队列

    • Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

  • Consumer:消费者,与以前一样,订阅队列,没有变化

  • Queue:消息队列也与以前一样,接收消息、缓存消息。


案例——FanoutExchange

步骤1. 在consumer中创建一个类,用于声明队列和交换机,并将队列与交换机进行绑定

@Configuration
public class FanoutConfig {// 声明交换机 itcast.fanout@Beanpublic FanoutExchange fanoutExchange() {return new FanoutExchange(("itcast.fanout"));}// 声明fanout.queue1@Beanpublic Queue fanoutQueue1() {return new Queue("fanout.queue1");}// 绑定队列1到交换机@Beanpublic Binding fanoutBinding1(Queue fanoutQueue1, FanoutExchange fanoutExchange) {return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);}// 声明fanout.queue2@Beanpublic Queue fanoutQueue2() {return new Queue("fanout.queue2");}// 绑定队列2到交换机@Beanpublic Binding fanoutBinding2(Queue fanoutQueue2, FanoutExchange fanoutExchange) {return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);}}

重新运行后,在RabbitMQ管理平台中可以看到已经生成该交换机,并且与两个队列绑定。

      

步骤2:在consumer服务的SpringRabbitListener中添加两个方法,作为消费者,对两个队列进行监听

@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg){System.out.println("消费者接收到fanout.queue1的消息:【" + msg + "】");
}@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg){System.out.println("消费者接收到fanout.queue2的消息:【" + msg + "】");
}

步骤3. 在publisher服务的SpringAmqpTest类中添加测试方法,将消息发送到交换机

@Test
public void testSendFanoutExchange() {//交换机名称String exchangeName = "itcast.fanout";//消息String message = "hello, every one!";//发送消息rabbitTemplate.convertAndSend(exchangeName,"", message);
}

运行该测试方法,可以在控制台中看到消费者成功接收到消息。 

总结

交换机的作用是什么?
1. 接收publisher发送的消息
2. 将消息按照规则路由到与之绑定的队列
3. 不能缓存消息,路由失败,消息丢失
4. FanoutExchange的会将消息路由到每个绑定的队列

绑定的队列声明队列、交换机、绑定关系的Bean是什么?
Queue、FanoutExchange、Binding


案例——DirectExchange

在Direct模型下:
1. 队列与交换机的绑定,不能是任意绑定了,而是要指定一个 RoutingKey(路由key)
2. 消息的发送方在向 Exchange发送消息时,也必须指定消息的 RoutingKey
3. Exchange不再把消息交给每一个绑定的队列,而是根据消息的 outing key 进行判断,只有队列的Routingkey 与消息的 Routing key 完全一致,才会接收到消息

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明。
步骤1. 在consumer的SpringRabbitListener中添加两个消费者,同时基于注解来声明队列和交换机

    @RabbitListener( bindings = @QueueBinding(value = @Queue(name = "direct.queue1"),exchange = @Exchange(name = "itcast.direct", type = ExchangeTypes.DIRECT),key = {"red", "blue"}))public void listenDirectQueue1(String msg) {System.out.println("消费者接收到direct.queue1的消息:【" + msg + "】");}@RabbitListener( bindings = @QueueBinding(value = @Queue(name = "direct.queue2"),exchange = @Exchange(name = "itcast.direct", type = ExchangeTypes.DIRECT),key = {"red", "yellow"}))public void listenDirectQueue2(String msg) {System.err.println("消费者接收到direct.queue2的消息:【" + msg + "】");}

步骤2. 在publisher服务的SpringAmqpTest类中添加测试方法

@Test
public void testSendDirectExchange() {//交换机名称String exchangeName = "itcast.direct";//消息String message = "hello, blue!";//发送消息rabbitTemplate.convertAndSend(exchangeName,"yellow", message);
}

当key为red时,控制台输出如下:

当key为blue时,控制台输出如下:

​​​​​​​

当key为yellow时,控制台输出如下:

总结

描述下Direct交换机与Fanout交换机的差异?
1. Fanout交换机将消息路由给每一个与之绑定的队列
2. Direct交换机根据RoutingKey判断路由给哪个队列
3. 如果多个队列具有相同的RoutingKey,则与Fanout功能类似

基于@RabbitListener注解声明队列和交换机有哪些常见注解?
@Queue、@Exchange


案例——TopicExchange

步骤1. 在consumer的SpringRabbitListener中添加两个消费者,同时基于注解来声明队列和交换机

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),exchange = @Exchange(name = "itcast.topic" ,type = ExchangeTypes.TOPIC),key = "china.#"
))
public void listenTopicQueue1(String msg) {System.out.println("消费者接收到Topic.queue1的消息:【" + msg + "】");
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),exchange = @Exchange(name = "itcast.topic" ,type = ExchangeTypes.TOPIC),key = "#.news"
))
public void listenTopicQueue2(String msg) {System.err.println("消费者接收到Topic.queue2的消息:【" + msg + "】");
}

步骤2. 在publisher服务的SpringAmqpTest类中添加测试方法

@Test
public void testSendTopicExchange() {//交换机名称String exchangeName = "itcast.topic";//消息String message = "世界新闻";//发送消息rabbitTemplate.convertAndSend(exchangeName,"world.news", message);
}

当key为china.news时,控制台输出如下:

 当key为china.weather时,控制台输出如下:

 当key为workd.news时,控制台输出如下:

 


消息转换器

Spring会把发送的消息序列化为字节发送给MQ,接收消息的时候,还会把字节反序列化为Java对象。只不过,默认情况下Spring采用的序列化方式是JDK序列化,而JDK序列化存在一些问题,如数据体积过大、有安全漏洞、可读性差等。

我们希望消息体的体积更小、可读性更高,因此可以使用JSON方式来做序列化和反序列化。

步骤1. 在publisher和consumer两个服务中都引入依赖:

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.10</version>
</dependency>

步骤2. 配置消息转换器,在启动类中添加一个Bean即可:

@Bean
public MessageConverter jsonMessageConverter(){return new Jackson2JsonMessageConverter();
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在Shopee平台上进行手机类目选品?

在Shopee平台上进行手机类目的选品是一个关键而复杂的任务。卖家需要经过一系列的策略和步骤&#xff0c;以确保选品的成功和销售业绩的提升。下面将介绍一些有效的策略&#xff0c;帮助卖家在Shopee平台上进行手机类目选品。 先给大家推荐一款shopee知虾数据运营工具知虾免费…

ffmpeg合成mp3音频,解决音频属性不一致问题

1. 需求&#xff0c;amr转成mp3&#xff0c;再将此mp3和其他mp3合成 2. 问题&#xff1a;拼接后的第一段音频可以播放&#xff0c;第二段自动跳过&#xff0c;无法播放。 3. 解决&#xff1a; 3.1 查看各文件属性 # 查看amr转为mp3文件的属性&#xff1a;ffprobe 文件名&am…

Pytorch从零开始实战18

Pytorch从零开始实战——人脸图像生成 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——人脸图像生成环境准备模型定义开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118&#…

[力扣 Hot100]Day20 旋转图像

题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在原地旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 出处 思路 旋转时每四个位置为一组进行swap操作&#xff0c;找好对…

【蓝桥杯51单片机入门记录】LED

目录 一、基础 &#xff08;1&#xff09;新建工程 &#xff08;2&#xff09;编写前准备 二、LED &#xff08;1&#xff09;点亮LED灯 &#xff08;2&#xff09;LED闪烁 延时函数的生成&#xff08;stc-isp中生成&#xff09; 实现 &#xff08;3&#xff09;流水灯…

OpenHarmony—开发及引用动态共享包

对于企业大型应用开发&#xff0c;有部分公共的资源和代码&#xff0c;只能在开发态静态共享&#xff0c;并且打包到每个依赖的HAP里&#xff0c;这样导致包体积较大&#xff0c;且有重复多份公共资源和代码重复打包到应用中。 为了解决运行态状态无法共享&#xff0c;以及减少…

2024美赛B题保姆级分析完整思路代码数据教学

2024美国大学生数学建模竞赛B题保姆级分析完整思路代码数据教学 B题&#xff1a;Searching for Submersibles 搜索潜水器 从给定的背景信息中&#xff0c;我们知道MCMS是一家位于希腊的公司&#xff0c;他们制造能够将人类运送到海洋深处的潜水艇。他们现在希望使用他们的潜水…

UML---用例图,类图

用例图 用例图&#xff08;Use Case Diagram&#xff09;主要描述系统的功能需求和参与者与系统之间的交互。它是用户与系统交互的最简表示形式&#xff0c;展现了用户和与他相关的用例之间的关系。用例图被视为系统的蓝图&#xff0c;通过它&#xff0c;人们可以获知系统不同种…

C语言·贪吃蛇游戏(下)

上节我们将要完成贪吃蛇游戏所需的前置知识都学完了&#xff0c;那么这节我们就开始动手写代码了 1. 程序规划 首先我们应该规划好我们的代码文件&#xff0c;设置3个文件&#xff1a;snack.h 用来声明游戏中实现各种功能的函数&#xff0c;snack.c 用来实现函数&#xff0c;t…

C# 根据USB设备VID和PID 获取设备总线已报告设备描述

总线已报告设备描述 DEVPKEY_Device_BusReportedDeviceDesc 模式 winform 语言 c# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Window…

2024美赛数学建模C题思路分析 - 网球的动量

1 赛题 问题C&#xff1a;网球的动量 在2023年温布尔登绅士队的决赛中&#xff0c;20岁的西班牙新星卡洛斯阿尔卡拉兹击败了36岁的诺瓦克德约科维奇。这是德约科维奇自2013年以来首次在温布尔登公开赛失利&#xff0c;并结束了他在大满贯赛事中历史上最伟大的球员之一的非凡表…

hivesql的基础知识点

目录 一、各数据类型的基础知识点 1.1 数值类型 整数 小数 float double(常用) decimal(针对高精度) 1.2 日期类型 date datetime timestamp time year 1.3 字符串类型 char varchar / varchar2 blob /text tinyblob / tinytext mediumblob / mediumtext lon…

EtherCAT FP介绍系列文章—UDP gateway

EtherCAT主站上的Mailbox Gateway功能&#xff0c;可以用于将EtherCAT mailbox相关协议从外部设备的工具通过邮箱网关路由到EtherCAT从站设备。在EtherCAT规范中定义的所有邮箱协议在此功能中都可用&#xff0c;例如CoE, FoE, VoE, SoE。 但是&#xff0c;这里特别注意的是Mai…

2024美赛数学建模E题思路分析 - 财产保险的可持续性

1 赛题 问题E&#xff1a;财产保险的可持续性 极端天气事件正成为财产所有者和保险公司面临的危机。“近年来&#xff0c;世界已经遭受了1000多起极端天气事件造成的超过1万亿美元的损失”。[1]2022年&#xff0c;保险业的自然灾害索赔人数“比30年的平均水平增加了115%”。[…

【STM32F103单片机】利用ST-LINK V2烧录程序 面包板的使用

1、ST‐LINK V2安装 参考&#xff1a; http://t.csdnimg.cn/Ulhhq 成功&#xff1a; 2、烧录器接线 背后有标识的引脚对应&#xff1a; 3、烧录成功 烧录成功后&#xff0c;按下核心板的RESET键复位&#xff01;&#xff01;&#xff01;即可成功&#xff01; 4、面包板的…

2024美赛数学建模D题思路源码

赛题目的 赛题目的&#xff1a; 问题描述&#xff1a; 解题的关键&#xff1a; 问题一. 问题分析 问题解答 问题二. 问题分析 问题解答 问题三. 问题分析 问题解答 问题四. 问题分析 问题解答 问题五. 问题分析 问题解答

2024美赛数学建模E题:房产保险的可持续性,思路全解,代码模型分析

2024美赛数学建模E题思路全解&#xff0c;代码模型分析,完整详细内容见文末名片 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 保险公司应该在承保保单时考虑多种因素&#xff0c;以确保公司的长期健康和稳定性。以下是一个可能的模式&#xff0c;以确…

合同网相关

一、集中式和分布式 集中式&#xff1a;由唯一的中央控制结点对整个系统进行控制。 分布式&#xff1a;对于多UCAV的分布式控制&#xff0c;基于合同网的市场竞拍机制是一种行之有效的方法。合同网的基本思想是将任务分配看作一个交易过程&#xff0c;通过“招标-投标-中标”…

docker相关问题解决(file exists、not a directory

背景 以下环境为wsl file exists 缓存没删干净 docker-compose down -v not a directory flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? 明明我确定报错指示的位置就是文件而不是文件夹...相当神奇的错误 …

嵌入式软件工程师面试题——2025校招社招通用(C/C++)(五十一)

说明&#xff1a; 面试群&#xff0c;群号&#xff1a; 228447240面试题来源于网络书籍&#xff0c;公司题目以及博主原创或修改&#xff08;题目大部分来源于各种公司&#xff09;&#xff1b;文中很多题目&#xff0c;或许大家直接编译器写完&#xff0c;1分钟就出结果了。但…