RabbitMQ高级篇
目录
确保发送者的可靠
为什么需要确保发送者的可靠性
RabbitMQ 的发送者重连机制配置
springAMQP实现发送者确认
MQ的可靠性
为什么需要实现MQ的可靠性?
数据持久化
Lazy Queue
核心思想
总结RabbitMQ 如何保证消息的可靠性
持久化
Lazy Queue
消息确认机制
消费者的可靠性
消费者确认机制的核心原理
消费者确认机制编辑
none 模式(无确认)
manual 模式(手动确认)
auto 模式(自动确认)
失败重试机制
失败消息处理策略
测试不出来?如何解决?
业务幂处理
为什么会产生重复消费?
使用唯一标识符(Message ID)
业务判断
延迟消息
使用插件完成
确保发送者的可靠
为什么需要确保发送者的可靠性
避免消息丢失
- 在分布式系统中,如果发送者未确认消息是否被 RabbitMQ 接收,可能会因为网络波动、RabbitMQ 服务异常等原因导致消息丢失。
- 消息丢失会导致数据不一致或业务逻辑中断,尤其是在支付系统、订单处理等关键场景下。
保证系统的可用性和稳定性
- 可靠性确保了生产者和消息队列之间的通信稳定性,即使在系统压力较大时,消息仍然能够被妥善处理。
RabbitMQ 的发送者重连机制配置
实际应用场景
临时网络波动
- 当网络抖动时,短时间内可能会导致连接失败,通过重试机制可以自动恢复连接。
RabbitMQ 短暂不可用
- RabbitMQ 重启或服务瞬间不可用时,通过重试可以避免消息丢失。
spring:rabbitmq:connection-timeout: 1s # 设置连接超时时间template:retry:enabled: true # 启用发送者重试机制initial-interval: 1000ms # 初始重试间隔为 1000ms (1 秒)multiplier: 2 # 每次重试间隔时间加倍max-attempts: 3 # 最大重试 3 次
Spring 配置说明
-
spring.rabbitmq.connection-timeout
配置与 RabbitMQ 建立连接时的超时时间,单位为毫秒或秒。在网络波动的情况下,如果连接超时,会触发重试机制。 -
spring.rabbitmq.template.retry.enabled
开启 RabbitMQ 发送消息的重试功能。当发送消息失败时,系统会按照配置的重试规则重新发送。
重试参数()
当multiplier为2的时候,相当于是计网当中CMSA/CD的截断二进制退避算法
-
initial-interval
第一次重试的间隔时间,单位为毫秒(ms)。比如配置为1000ms
,表示第一次失败后等待 1 秒开始重试。 -
multiplier
每次重试间隔时间的倍增系数。例如配置为1
,说明每次重试的间隔时间是固定的;如果配置为2
,那么每次间隔时间会加倍。计算公式:
下一次重试间隔 = initial-interval × multiplier
springAMQP实现发送者确认
MQ的可靠性
为什么需要实现MQ的可靠性?
内存中消息会丢失:
- RabbitMQ 默认将消息存储在内存中(非持久化),以降低延迟。
- 如果 MQ 宕机,内存中的消息会被清空,从而丢失。
内存空间有限,可能导致消息积压:
- 如果消费者处理过慢或不可用,内存中的消息无法被及时消费,消息会积压,占用 RabbitMQ 的内存。
- 当内存使用达到限制时,RabbitMQ 可能会触发流控(Flow Control),甚至出现系统阻塞或崩溃。RabbitMQ 会将这些消息被动地写入磁盘,以缓解内存压力。当队列中消息积压严重时,RabbitMQ 被迫将大量消息写入磁盘(被动持久化),磁盘的读写速度可能无法跟上队列的处理速度,从而引发 队列阻塞。
- 为了解决这个问题才有了同步持久化策略,不会导致消息队列阻塞
同步持久化策略:
- 消息到达时立即写入磁盘,消除了被动写入导致的延迟和瓶颈。
- 优点:可靠性高,不会因磁盘写入延迟导致队列阻塞。
- 缺点:性能略低,需要优化磁盘性能来减小延迟。
数据持久化
在 Spring AMQP 中,默认的可靠性措施已经覆盖了 队列持久化 和 自动重连,你只需要在以下两种情况下手动配置:
确保消息可靠传递和存储:
- 需要显式声明消息为持久化(
PERSISTENT
)。 - 需要注意的是,在java代码中我们需要自定义构建消息来发送临时消息。
public void sendPersistentMessage(String exchange, String routingKey, String messageContent) {// 创建持久化消息Message message = MessageBuilder.withBody(messageContent.getBytes()).setDeliveryMode(MessageProperties.DeliveryMode.PERSISTENT) // 设置为持久化.build();// 发送消息rabbitTemplate.send(exchange, routingKey, message);System.out.println("Sent persistent message: " + messageContent);}
Lazy Queue
Lazy Queue 是 RabbitMQ 的一种队列模式,主要用于优化 消息持久化策略 的缺点和高消息积压场景下的性能问题。它将消息尽可能存储在磁盘上,而不是内存中,从而减少内存占用和避免内存不足导致的队列阻塞。
Lazy Queue 设计的目标
Lazy Queue 是为了解决上述问题的一种优化方案,其目标是最大限度地减少内存占用,优先使用磁盘存储消息,从而解决持久化策略的缺点。
核心思想
消息直接写入磁盘:
- Lazy Queue 会在消息到达时直接将其存储在磁盘上,而不是先存储在内存中。
- 只有在需要消费时,才会将消息从磁盘加载到内存中。
延迟加载消息:
- 消息只有在消费者需要处理时才会被加载到内存中,而不是全部预加载。
- 这减少了内存占用,同时避免了磁盘与内存之间频繁切换的问题。
总结RabbitMQ 如何保证消息的可靠性
持久化
- 确保消息(需要手动配置)、队列和交换机在 RabbitMQ 重启后依然存在。
- 优点:保障消息不会因服务中断而丢失。
- 缺点:磁盘 IO 开销增加,可能影响性能。
Lazy Queue
- 解决持久化策略中内存占用高的问题,消息优先存储在磁盘中。
- 优点:减少内存消耗,适合消息积压场景。
- 缺点:磁盘 IO 性能略低于内存操作,不适合高吞吐实时场景。
消息确认机制
- 保证消息从生产者到 RabbitMQ 的可靠传递。
- 优点:生产者可以通过 ACK 确认消息是否成功到达 RabbitMQ。一般是可以成功到达除是程序员配置错误。因此我们可以根据实际情况选择。
- 缺点:增加网络和确认延迟。
消费者的可靠性
消费者确认机制的核心原理
消费者确认机制的目的是确保消息被成功消费后,RabbitMQ 可以安全地将消息从队列中移除。如果消息处理失败,则可以选择重新投递或丢弃,以实现可靠的消息消费。
确认机制的三种状态
ACK(Acknowledgement)
- 描述:消息已成功处理,通知 RabbitMQ 可以安全删除消息。
- 结果:RabbitMQ 将消息从队列中移除。
NACK(Negative Acknowledgement)
- 描述:消息处理失败,消费者通知 RabbitMQ 需要重新投递消息。
- 结果:消息重新进入队列,供其他消费者或当前消费者再次处理。
REJECT
- 描述:消息处理失败,但消费者明确表示拒绝消息。例如:格式问题
- 结果:消息从队列中删除,不会重新投递。
消费者确认机制
在 RabbitMQ 的消费者确认机制中,消费者需要通知 RabbitMQ 消息是否被成功处理。Spring AMQP 通过 acknowledge-mode
提供了三种消息确认模式:
none 模式(无确认)
特点:
- 消息推送到消费者后,RabbitMQ 会立即将其标记为已确认,无论消息是否被成功处理。
- 极不安全,因为如果消费者出现异常或宕机,消息可能会丢失。
适用场景:不推荐使用,除非对消息丢失完全没有影响。
manual 模式(手动确认)
特点:
- 消费者需要手动调用 RabbitMQ 提供的 API(如
basicAck
、basicNack
、basicReject
)来确认消息是否被成功处理。 - 优点:可以精确控制消息的确认时机,适合对可靠性要求高的场景。
实现方式:
- 在
@RabbitListener
方法中捕获异常,根据业务逻辑决定发送ACK
、NACK
或REJECT
。
auto 模式(自动确认)
特点:
- Spring AMQP 默认使用 AOP 对消息处理方法进行代理,消息处理成功后会自动发送
ACK
。 - 如果方法抛出异常,Spring AMQP 会自动发送
NACK
或REJECT
。 -
适用场景:适合消息可靠性要求不高、处理逻辑较简单的场景。
实现方式:无需手动确认,Spring 会根据方法执行结果自动处理。
spring:rabbitmq:host: # 你的虚拟机IPport: 5672 # 端口virtual-host: /hmall # 虚拟主机username: hmall # 用户名password: 123 # 密码listener:simple:prefetch: 1 # 控制消费者预取的消息数量,处理完一条再处理acknowledge-mode: auto
消费者处理失败时,消息被 NACK 并重新入队,RabbitMQ 会不断尝试将消息重新投递给消费者,导致消息反复处理失败,最终对 RabbitMQ 和服务产生巨大的负担。因此我们可以通过设置失败重试机制,限制消息重试次数
失败重试机制
Spring AMQP 提供了 重试机制,可以限制消费者的最大重试次数。如果消息在多次重试后仍然失败,可以转移到死信队列或记录到日志中。
如果重试了最大次数了之后还是不能成功会直接把消息丢弃了,因此我们还需要配置重试失败处理策略。
失败消息处理策略
Spring AMQP 提供了三种常见的失败消息处理策略:
RejectAndDontRequeueRecoverer
(默认策略):丢弃消息。ImmediateRequeueMessageRecoverer
:消息重新入队。RepublishMessageRecoverer
:将消息转移到指定的交换机。原来的队列中不会再有这个消息。
选择建议:
- 非关键场景:使用默认的
RejectAndDontRequeueRecoverer
。 - 临时错误场景:使用
ImmediateRequeueMessageRecoverer
,重新入队。 - 关键场景:使用
RepublishMessageRecoverer
,将消息投递到死信队列或专用的交换机。
配置消费者重试机制
spring:rabbitmq:listener:simple:retry:enabled: truemax-attempts: 5 # 最大重试次数initial-interval: 1000ms # 初始重试间隔multiplier: 2.0 # 每次重试间隔倍增max-interval: 10000ms # 最大重试间隔
结合 MessageRecoverer
在重试失败时,指定使用的消息恢复策略:
@Configuration
public class ErrorMessageConfiguration {@Beanpublic DirectExchange errorExchange() {return new DirectExchange("error.direct"); // 声明一个 Direct 类型的交换机,名称为 "error.direct"}@Beanpublic Queue errorQueue() {return new Queue("error.queue",true); // 声明一个队列,名称为 "error.queue"}@Beanpublic Binding errorQueueBinding(Queue errorQueue, DirectExchange errorExchange) {return BindingBuilder.bind(errorQueue).to(errorExchange).with ("error"); // 将队列 "error.queue" 和交换机 "error.direct" 绑定,路由键为 "error"}@Beanpublic MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {System.out.println("执行了消息恢复器!!!");return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");// 配置一个消息恢复器,将消费失败的消息重试多次后投递到 "error.direct" 交换机,路由键为 "error"}
}
测试不出来?如何解决?
如果你和代码写的一样或者代码没有明显的错误,但是就是测试不出来。
可以选择将simple.queue删除之后,在重新新建并且重新发送消息。
在 RabbitMQ 中,Purge Messages
只会清空处于 Ready 状态(也就是未被消费者接收或未投递中的消息)。如果有消息已经分配给消费者,处于 Unacked 状态,RabbitMQ 并不会通过 Purge
操作将它们从队列里移除。也就是说,Purge
并不能清除还在进行中的消费或处于 Unacked 状态的消息。
因此,当你点击 Purge Messages 时,如果队列里大部分消息都处于 Unacked 状态(可能由于消费者一直没 ACK),Purge 操作其实没有把这些 Unacked 消息移除。它们依然存在,消费者再次重连或者容器重启时,RabbitMQ 还会继续投递。
反之,当你删除并重新创建这个队列时,RabbitMQ 会彻底销毁所有该队列关联的消息(不管它们是 Ready 还是 Unacked),然后新建一个空队列,之前的消息自然就不复存在,手动删队列再建”可以成功清空消息,而 Purge 不行的现象。
业务幂处理
幂等性 是指在分布式系统中,某一操作无论被执行一次还是多次,其产生的效果是相同的。在使用 RabbitMQ 或其他消息队列时,消费者可能会因重试、重复投递等原因处理相同的消息多次。为了保证系统数据的一致性和可靠性,需要解决幂等性问题。
为什么会产生重复消费?
RabbitMQ 和其他消息队列可能会因为以下原因导致消息重复消费:
消息重试机制:
- 消费者处理失败时,消息会被重新投递。
- 例如:消息超时、消费者抛出异常。
网络问题:
- 如果 RabbitMQ 没有收到消费者的
ACK
,会认为消息未被成功处理,并重新投递。
消息重复发送:
- 生产者在发送消息时,如果未正确处理确认机制,可能会发送相同的消息多次。
使用唯一标识符(Message ID)
生产端设置唯一消息 ID:
- 在生产消息时,为每条消息生成一个唯一的 ID(通常是 UUID)。
- 该
Message ID
会作为消息的属性,和消息一起发送到 RabbitMQ。
消费端接收唯一消息 ID:
- 消费者在处理消息时,从消息的属性中提取
Message ID
。 - 利用这个
Message ID
在数据库或缓存(Redis)中查询是否已处理过该消息。
去重逻辑:
- 如果
Message ID
已存在,说明消息是重复的,直接忽略不处理。 - 如果
Message ID
不存在,说明消息是新的,正常处理,并将Message ID
标记为已处理。 - 如果消息只需短期去重(如几天内不重复):使用 Redis,并设置合理的过期时间。
- 如果需要长期保存处理状态:使用 MySQL 或其他关系型数据库,结合唯一约束实现幂等性。
配置消息转换器
通过 Jackson2JsonMessageConverter
设置消息的 Message ID
:
作用:
Jackson2JsonMessageConverter
会在消息体序列化为 JSON 时自动生成一个唯一的Message ID
,并附加到消息属性中。- 如果消息体已经包含一个业务 ID(如订单号),也可以使用该 ID 作为去重标识。
@Bean
public MessageConverter messageConverter() {Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();jjmc.setCreateMessageIds(true); // 自动生成消息 IDreturn jjmc;
}
消费者代码
在消费者中,通过 MessageProperties
获取消息的唯一 ID,并处理去重逻辑:
@RabbitListener(queues = "simple.queue")
public void listenSimpleQueue(Message message) {// 获取消息的唯一 IDString messageId = message.getMessageProperties().getMessageId();String body = new String(message.getBody());log.info("监听simple.queue的消息. ID: [{}]", messageId);log.info("监听simple.queue的消息: [{}]", body);// 模拟处理逻辑throw new RuntimeException("我要故意出错!");// 存入数据库或者Redis当中
}
业务判断
核心思路
根据业务的唯一标识符(如 orderId
)查询业务状态:
- 消费者处理消息时,通过
orderId
查询订单信息。
判断订单状态是否已被处理:
- 如果订单状态表明该订单已经处理过(如状态为已支付),则直接忽略当前消息。
- 如果订单状态表明该订单尚未处理,则正常处理消息。
更新业务状态:
- 在消息成功处理后,将订单状态标记为已处理(如更新为“已支付”状态)。
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "trade.pay.success.queue", durable = "true"),exchange = @Exchange(name = "pay.direct"),key = "pay.success"
))
public void listenPaySuccess(Long orderId) {// 1. 查询订单Order order = orderService.getById(orderId);// 2. 判断订单状态,是否为未支付if (order == null || order.getStatus() != 1) {// 如果订单不存在,或者状态不为“待支付”(1),则直接忽略return;}// 3. 标记订单状态为已支付orderService.markOrderPaySuccess(orderId);
}
基于业务判断实现幂等性的主要局限性是强依赖于业务状态字段的设计,并且在动态数据、高并发场景下可能难以准确实现幂等性控制。例如,怎么保证库存的幂等性?这种业务判断不能保证库存这种动态数据的变化。因此,在实际项目中,业务判断通常作为一种基础手段,结合唯一消息 ID、分布式锁、缓存或事务机制共同实现幂等性,才能保证系统的可靠性和高效性。
延迟消息
为什么需要消息延迟方案?
在一般的交易服务流程中,当用户下单后,会进入支付环节。如果支付成功,理论上支付服务会通过消息队列(MQ)将消息发送给交易服务,以通知交易服务更新订单状态为“已支付”。
现在思考这样一种场景:
如果支付服务因某种未知原因无法向交易服务发送消息,可能会导致以下两个问题:
-
数据不一致
支付服务已经扣款,但交易服务无法及时感知支付结果,从而无法更新订单状态为“已支付”。此时,用户的支付记录和订单状态不匹配,导致系统数据不一致。 -
系统资源被占用
交易服务在等待支付服务的消息确认时,订单的状态可能会一直停留在“待支付”或“支付中”,导致对应的库存被锁定。其他用户在尝试购买该商品时,可能会因为库存不足而无法完成下单,从而影响系统的正常运行与用户体验。
所以交易服务需要过一段时间之后去查询支付服务的支付状态。因此需要消息延迟。
如何去查询支付状态呢?
交易服务通过 FeignClient
调用支付服务的接口,查询支付状态。
具体实现:day07-MQ高级 - 飞书云文档 (feishu.cn)
FeignClient的详细讲解:
springCloud特色知识记录(基于黑马教程2024年)-CSDN博客
消息延迟方案在分布式系统中起到以下重要作用:
延迟执行任务:
- 在一些业务场景中,需要对某些任务进行延迟处理。例如,在电商系统中,如果用户下单后未在一定时间内支付,则自动取消订单。
使用插件完成
day07-MQ高级 - 飞书云文档 (feishu.cn)
根骨以上文档的——DelayExchange插件的安装可以安装并且启动插件
官方文档:
Scheduling Messages with RabbitMQ | RabbitMQ
注意:如果你使用的MQ的版本要和插件的版本不冲突
测试生产者(发送消息)
在 RabbitMQ 的延迟队列中,延迟时间的核心是通过 消息属性 来实现的,具体来说是设置 x-delay
属性,定义消息在队列中延迟的时间。
@Testvoid testSendDelayMessageByPlugin(){rabbitTemplate.convertAndSend("delay.direct","hi","hello",message ->{message.getMessageProperties().setDelay(10000);return message;});}
rabbitTemplate.convertAndSend
:
参数:
- RabbitTemplate 是 Spring 提供的用于与 RabbitMQ 交互的工具类。
convertAndSend
方法用于向指定的交换机发送消息。delay.direct
:指定目标交换机的名称。hi
:指定路由键,用于匹配队列。hello
:发送的消息内容。message -> {...}
:消息后处理器,用于对消息属性进行修改。
设置延迟时间:
message.getMessageProperties().setDelay(10000)
:
- 通过
MessageProperties
的setDelay
方法设置延迟时间(单位为毫秒)。 - 在此示例中,延迟时间设置为 10000 毫秒(即 10 秒)。
返回修改后的消息:
- Lambda 表达式返回处理后的
Message
对象,将其发送到指定的交换机和队列。
测试消费者(接收消息)
@RabbitListener(bindings = @QueueBinding(value = @Queue(name="delay.queue",durable = "true"),exchange = @Exchange(name = "delay.direct",delayed = "true"),key = {"hi"}
))
public void listenDelayQueue(String message){log.info("listenDelayQueue接收到信息【{}】",message );
}
监听延迟队列:通过 @RabbitListener
注解,Spring Boot 应用可以监听名为 delay.queue
的队列,处理其中的消息。
绑定延迟交换机:
- 使用
@QueueBinding
将队列delay.queue
绑定到延迟交换机delay.direct
。 - 指定路由键为
"hi"
,只有匹配此路由键的消息会进入队列。 delayed="true"
:启用延迟特性,使交换机支持消息延迟。
接收并处理消息:
- 方法
listenDelayQueue
会在有消息到达队列时被触发,消费消息并打印日志。
使用场景示例
订单超时取消:
- 用户下单后,消息进入延迟队列,设置延迟时间为支付时间限制(如 30 分钟)。若支付完成,移除消息;否则到时间后取消订单。
延迟通知:
- 在一段时间后提醒用户未完成的操作(如未完成注册或填写资料)。
自动处理过期内容:
- 处理定期失效的资源(如清理过期缓存、关闭未使用的会话等)。
相关文章:
RabbitMQ高级篇
目录 确保发送者的可靠 为什么需要确保发送者的可靠性 RabbitMQ 的发送者重连机制配置 springAMQP实现发送者确认 MQ的可靠性 为什么需要实现MQ的可靠性? 数据持久化 Lazy Queue 核心思想 总结RabbitMQ 如何保证消息的可靠性 持久化 Lazy Queue 消息…...
任务调度系统Quartz.net详解2-Scheduler、Calendar及Listener
任务调度系统Quartz.net详解2-Scheduler、Calendar及Listener Scheduler 调度器scheduler是Quartz中的独立工作容器,所有的Trigger和Job都需要注册到scheduler中才能工作。我们可以通过SchedulerFactory来获取scheduler实例。如下: //1.获取默认的标准…...
服务器出现蓝屏现象的原因有什么?
当服务器定期出现蓝屏的现象,则会影响到企业业务的连续性,同时还可能会导致重要数据信息丢失和系统稳定性下降,是一种较为复杂的技术问题,本文就来探讨一下导致服务器出现蓝屏的原因都有什么。 服务器出现蓝屏有可能是硬件出现了故…...
IP 地址与蜜罐技术
基于IP的地址的蜜罐技术是一种主动防御策略,它能够通过在网络上布置的一些看似正常没问题的IP地址来吸引恶意者的注意,将恶意者引导到预先布置好的伪装的目标之中。 如何实现蜜罐技术 当恶意攻击者在网络中四处扫描,寻找可入侵的目标时&…...
探索数据存储的奥秘:深入理解B树与B+树
key value 类型的数据红黑树(最优二叉树,内存最优),时间复杂度:O(logn),调整方便;一个结点分出两个叉B树一个节点可以分出很多叉数据量相等的条件下:红黑树的层数很高&am…...
mac学习芋道源码记录
nodejs安装 v16.20.0 cd yudao-ui-admin-vue2 node install -g yarn yarn install npm run local改配置不然node install -g yarn报错 前往-前往文件夹-/Library 创建 /nodejs/node_global /nodejs/node_cache npm config set prefix /Library/nodejs/node_global npm c…...
CCF 赛事介绍
CCF 赛事介绍 中国计算机学会(CCF)举办了诸多具有影响力的赛事,面向不同年龄段与群体,各有其特色要求。 一、青少年编程启蒙类 CCF 编程能力等级认证(GESP): 适合年龄:涵盖中小学…...
MySQL表的约束
目录 一、空属性 二、默认值 三、列描述 四、zerofill 五、主键 六、自增长 七、唯一键 八、外键 一、空属性 两个值:null(默认的)和not null(不为空) 数据库默认字段基本都是字段为空,但是实际开发时,尽可能…...
相互带节奏
有些单词在发音方面是相互带节奏的 【1】 broccoli n.西兰花Berklee n.伯克利 Berklee College of Music 伯克利音乐学院 【2】 college n.大学,学院colleague n.同事,僚 league n.联合会,联赛;联盟,同盟 【3】…...
秒懂虚拟化(二):服务器虚拟化、操作系统虚拟化、服务虚拟化全解析,通俗解读版
秒懂虚拟化(一):从概念到网络、存储虚拟化全解析,通俗解读版-CSDN博客这篇文章学习了虚拟化的概念、网络虚拟化和存储虚拟化,本节将继续学习服务器虚拟化、操作系统虚拟化、服务虚拟化。 1、服务器虚拟化 服务器虚拟…...
ubuntu 配置OpenOCD与RT-RT-thread环境的记录
1.git clone git://git.code.sf.net/p/openocd/code openocd 配置gcc编译环境 2. sudo gedit /etc/apt/source.list #cdrom sudo apt-get install git sudo apt-get install libtool-bin sudo apt-get install pkg-config sudo apt-install libusb-1.0-0-dev sudo apt-get…...
优化 MySQL 的慢查询
文章目录 1. 分析慢查询日志2. 优化查询语句3. 优化表结构4. 调整服务器参数5. 数据库引擎选择6. 缓存策略7. 定期维护数据库 1. 分析慢查询日志 首先,要开启 MySQL 的慢查询日志,以便能够记录执行时间超过阈值的查询语句。可以通过修改 MySQL 配置文件…...
【机器学习】聚类评价指标之福尔克斯–马洛斯指数(Fowlkes–Mallows Index, FMI)
福尔克斯–马洛斯指数(Fowlkes–Mallows Index, FMI)是一种用于评估聚类结果与实际标签之间一致性的指标。FMI 值可以用于衡量聚类的准确性,特别是在有真值标签的监督评估场景中。 计算公式 FMI 的计算基于以下公式: 其中&#…...
vue3模板引用ref
1.访问模板引用 要在组合式 API 中获取引用,我们可以使用辅助函数 useTemplateRef() 只可以在组件挂载后才能访问模板引用 <script setup> import { useTemplateRef, onMounted } from vue// 第一个参数必须与模板中的 ref 值匹配 const input useTempla…...
20250111英语学习
place check in window seat; aisle seat boarding pass 登机牌 boarding pass depart from terminal C Gate 4 (Gate door entre to the plane) place : Check in window seat boarding pass 登机牌 depart from terminal C Gate 4 (Gate door entre to the plane) you…...
【Rust自学】11.6. 控制测试运行:并行和串行(连续执行)测试
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 11.6.1. 控制测试的运行方式 cargo test和cargo run一样,cargo test也会编译代码并生成一个二进制文件用于测试,…...
CSS3 弹性盒子
CSS3 弹性盒子 介绍 CSS3 弹性盒子(Flexbox)是一种用于布局设计的强大工具。它提供了一种更加高效的方式来对容器内的子元素进行排列、对齐和分配空间。Flexbox 的设计目标是提供一种统一的布局模型,能够适应不同屏幕尺寸和设备类型&#x…...
LabVIEW 系统诊断
LabVIEW 系统诊断是指通过各种工具和方法检测、评估、分析和解决 LabVIEW 程序和硬件系统中可能存在的故障和性能问题。系统诊断不仅涵盖软件层面的调试与优化,还包括硬件交互、数据传输、实时性能等方面的检查和分析。一个成功的系统诊断能够显著提升LabVIEW应用程…...
UE5中制作地形材质
在创作大场景内容时,地形的设计和优化是至关重要的一步。利用UE中的地形系统,开发者能够高效地创建复杂的地形形态,同时保持游戏的性能和视觉效果。 1.在创建地形之前,先新建一个地形使用的混合材质球,添加节点Landsc…...
【题解】AT_abc388_e AtCoder Beginner Contest ABC388 E Simultaneous Kagamimochi
题目大意 题目传送门——原题面链接 建议阅读本次比赛 C 题题面。 有 N N N 块米糕,按大小升序排列,第 i i i 块米糕的大小为 A i A_i Ai。 现在定义“堆叠式米糕”如下: 首先,选出两个米糕 A A A 和 B B B࿰…...
2025年01月11日Github流行趋势
项目名称:xiaozhi-esp32 项目地址url:https://github.com/78/xiaozhi-esp32项目语言:C历史star数:2433今日star数:321项目维护者:78, MakerM0, whble, nooodles2023, Kevincoooool项目简介:构建…...
Uniapp中实现加载更多、下拉刷新、返回顶部功能
一、加载更多: 在到达底部时,将新请求过来的数据追加到原来的数组即可: import {onReachBottom } from "dcloudio/uni-app";const pets ref([]); // 显示数据function network() {uni.request({url: "https://api.thecatap…...
哈希表及模拟实现
目录 一、哈希表的概念 二、模拟实现哈希表 1.开放地址法 (1)哈希表的数据加上状态标志 (2)哈希表扩容:载荷因子 (3)哈希函数:不同数据类型转换为整型 (4)完整代码 2.链地址法(哈希桶) (1)哈希表扩容:载荷因子…...
鸿蒙面试 2025-01-09
鸿蒙分布式理念?(个人认为理解就好) 鸿蒙操作系统的分布式理念主要体现在其独特的“流转”能力和相关的分布式操作上。在鸿蒙系统中,“流转”是指涉多端的分布式操作,它打破了设备之间的界限,实现了多设备…...
Apache XMLBeans 一个强大的 XML 数据处理框架
Apache XMLBeans 是一个用于处理 XML 数据的 Java 框架,它提供了一种方式将 XML Schema (XSD) 映射到 Java 类,从而使得开发者可以通过强类型化的 Java 对象来访问和操作 XML 文档。下面将以一个简单的案例说明如何使用 Apache XMLBeans 来解析、生成和验…...
基于视觉惯性 SLAM(VSLAM)、相机和 IMU 数据的融合执行 6 自由度位姿跟踪
案例来源:https://spectacularai.github.io/docs/sdk/wrappers/oak.html 适配相机:带IMU的 OAK-D 系列相机 基于视觉惯性 SLAM(VSLAM)、相机和 IMU 数据的融合执行 6 自由度位姿跟踪 ~~~~~~~(分界线)~~~~~…...
MySQL--》理解锁机制中的并发控制与优化策略
锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中除了传统的计算机资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突…...
2、第一个GO 程序
引言 接下里我们就用Go Land 工具,开发第一个GO程序。大家也可以用其他的开发工具,例如 Vs Code 1、新建项目 第一个是选择你的程序保存位置 (不要有中文)。 第二个是你的Go的编译器的安装地址。 选择完毕后,就点击 …...
解决nginx多层代理后应用部署后访问发现css、js、图片等样式加载失败
一般是采用前后端分离部署方式,被上一层ng代理后,通过域名访问报错,例如:sqx.com.cn/应用代理路径。 修改nginx配置,配置前端页面的路径: location / {proxy_pass http://前端页面所在服务器的IP:PORT;pro…...
【Notepad++】Notepad++如何删除包含某个字符串所在的行
Notepad如何删除包含某个字符串所在的行 一,简介二,操作方法三,总结 一,简介 在使用beyoundcompare软件进行对比的时候,常常会出现一些无关紧要的地方,且所在行的内容是变化的,不方便进行比较&…...
Python的秘密基地--[章节11] Python 性能优化与多线程编程
第11章:Python 性能优化与多线程编程 在开发复杂系统时,性能优化和并发编程是不可忽视的重点。Python 提供了多种工具和技术用于优化代码性能,并通过多线程、多进程等方式实现并发处理。本章将探讨如何在 Python 中提升性能,并实…...
【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...
初学stm32 --- ADC模拟/数字转换器工作原理
目录 常见的ADC类型 并联比较型工作示意图 逐次逼近型工作示意图 ADC的特性参数 STM32各系列ADC的主要特性 ADC框图简介 参考电压/模拟部分电压 输入通道( F1为例) 转换序列(F1为例) 规则组和注入组执行优先级对比 规则…...
【MySQL】SQL菜鸟教程(一)
1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…...
BM25(Best Match 25):信息检索的排序函数;稠密矩阵检索技术:RoBERTa
BM25(Best Match 25):信息检索的排序函数 常用于搜索引擎等场景,以下是关于它检索的内容及举例说明: 一、BM25检索的内容 文本数据: 文档集合:可以是大量的网页、学术论文、新闻文章、书籍内容等各种形式的文本集合。例如,一个学术搜索引擎可能会使用BM25对包含数百万…...
高级软件工程-复习
高级软件工程复习 坐标国科大,下面是老师说的考试重点。 Ruby编程语言的一些特征需要了解要能读得懂Ruby程序Git的基本命令操作知道Rails的MVC工作机理需要清楚,Model, Controller, View各司什么职责明白BDD的User Story需要会写,SMART要求能…...
Java常用设计模式
单例模式 单例模式就是: 在程序运行期间, 某些类有且最多只有一个实例对象 饿汉模式(静态常量) 饥饿模式又称为饿汉模式, 指的是JVM在加载类的时候就完成类对象的创建 //饿汉式(静态常量) public class Singleton1 {//构造器私有化,外部不能newprivate Singleto…...
29.Java 集合线程安全(ArrayList 类线程安全问题处理方案、HashSet 、HashMap 类线程安全问题处理方案)
一、ArrayList 类线程安全问题 1、概述 ArrayList 类存在线程安全问题 2、异常演示 ListNoSafeTest.java,演示 ArrayList 类线程安全问题 package com.my.listsafe;import java.util.ArrayList; import java.util.UUID;public class ListNoSafeTest {public st…...
解锁企业数字化转型新力量:OpenCoze(开源扣子)
在当今数字化浪潮席卷之下,企业对于高效管理和协同运作的需求愈发迫切,而开源技术正逐渐成为众多企业破局的关键利器。今天,想给大家介绍一款极具潜力的开源项目 ——OpenCoze,中文名称 “开源扣子”。 一、OpenCoze 是什么&…...
Docker 使用Dockerfile创建镜像
创建并且生成镜像 在当前目录下创建一个名为Dockerfile文件 vi Dockerfile填入下面配置 # 使用 CentOS 作为基础镜像 FROM centos:7# 设置工作目录 WORKDIR /app# 复制项目文件到容器中 COPY bin/ /app/bin/ COPY config/ /app/config/ COPY lib/ /app/lib/ COPY plugin/ /a…...
linux网络 | https前置知识 | 数据加密与解密、数据摘要
前言:本节内容讲述https的相关内容。 https博主会着重讲解https如何让一个请求和一个响应能够安全的进行交互。 https博主将用两篇文章进行讲解。本篇是两篇中第一篇。会把http的安全问题引出来, 然后说一下https的基本解决方法。 下面废话不多说, 开始我…...
01 Oracle自学环境搭建(Windows系统)
1 Oracle12C安装 1.1 下载 官网地址:https://www.oracle.com/ 进入官网→Resource→Customer Downloads 如果没有登录,会提示登录后后才能下载 选择适合自己的版本(我电脑是Windows系统 64位) 选择需要的安装包进行下载 双击下载…...
负载均衡原理及算法
什么是负载均衡? 负载均衡 指的是将用户请求分摊到不同的服务器上处理,以提高系统整体的并发处理能力以及可靠性。负载均衡服务可以有由专门的软件或者硬件来完成,一般情况下,硬件的性能更好,软件的价格更便宜&#x…...
STM32第5章、IWDG
一、简介 IWDG:全称是Independent watchdog,即独立看门狗。本质上是一个能产生系统复位信号的计数器。 特性: 是一个递减计数器。 时钟信号由独立的RC振荡器提供,可在待机和停止模式下运行。 看门狗被激活后,当递减计…...
[python3]Uvicorn库
Uvicorn 是一个用于运行 ASGI(Asynchronous Server Gateway Interface)应用程序的轻量级服务器。ASGI 是 Python Web 应用程序接口的一种扩展,它不仅支持传统的同步 Web 请求处理,还支持异步请求处理、WebSockets 以及 HTTP/2。 h…...
openEuler 22.04使用yum源最快速度部署k8s 1.20集群
本文目的 openEuler的官方源里有kubernetes 1.20,使用yum源安装是最快部署一个k8s集群的办法 硬件环境 主机名系统架构ipmasteropenEuler release 22.03 (LTS-SP2)arm192.168.3.11edgeopenEuler release 22.03 (LTS-SP2)arm192.168.3.12deviceopenEuler release 22.…...
【深度学习】数据预处理
为了能用深度学习来解决现实世界的问题,我们经常从预处理原始数据开始, 而不是从那些准备好的张量格式数据开始。 在Python中常用的数据分析工具中,我们通常使用pandas软件包。 像庞大的Python生态系统中的许多其他扩展包一样,pan…...
Oracle:ORA-00904: “10“: 标识符无效报错详解
1.报错Oracle语句如下 SELECT YK_CKGY.ID,YK_CKGY.DJH,YK_CKGY.BLRQ,YK_CKGY.ZBRQ,YK_CKGY.SHRQ,YK_CKGY.YT,YK_CKGY.ZDR,YK_CKGY.SHR,YK_CKGY.BZ,YK_CKGY.JZRQ,YK_CKGY.ZT,YK_CKGY.CKLX,(case YK_CKGY.CKLXwhen 09 then药房调借when 02 then科室退药when 03 then损耗出库when…...
CentOS 7 下 Nginx 的详细安装与配置
1、安装方式 1.1、通过编译方式安装 下载Nginx1.16.1的安装包 https://nginx.org/download/nginx-1.16.1.tar.gz 下载后上传至/home目录下。 1.2、通过yum方式安装 这种方式安装更简单。 2、通过编译源码包安装Nginx 2.1、安装必要依赖 sudo yum -y install gcc gcc-c sudo…...
Vue.js:现代前端开发的灵活框架
大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | A…...