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

MQ消息的不可靠性发生情况与解决方案

文章目录

    • 问题:
    • 可能出现的情况:
  • 解决流程与兜底方案
    • 第一个方面:确保生产者一定把消息发送到MQ
      • 1.生产者重试机制
      • 2.生产者确认机制
    • 第二个方面:确保MQ不会将消息丢失
      • 数据持久化
        • 交换机持久化
        • 2.队列持久化
        • 3.消息持久化
      • LazyQueue
        • 控制台配置Lazy模式
        • SpringAMQP代码声明Lazy模式
        • 更新已有队列为lazy模式
    • 第三方面.确保消费者一定要处理消息
      • 消费者确认机制(**Consumer Acknowledgement**)
      • 失败重试机制
      • 失败处理策略:
    • 业务幂等性
      • 唯一消息id:
      • 业务判断:
    • 兜底方案
    • 总结:

问题:

  • 我们该如何确保MQ消息的可靠性
  • 如果真的发送失败,有没有其它的兜底方案?

可能出现的情况:

消息丢失的可能性:

发送消息的流程如图所示:

在消息发送的流程中从生产者到消费者每一步都有可能导致消息丢失:

可能的情况:

  • 生产者发送消息时丢失:
    • **网络问题:**生产者发送消息时连接MQ失败
    • 生产者发送消息到达MQ后未找到**Exchange**
    • 生产者发送消息到达MQ的**Exchange**后,未找到合适的**Queue**
    • 消息到达MQ后,处理消息的进程发生异常
  • MQ导致消息丢失:
    • 消息到达MQ,保存到队列后,尚未消费就突然宕机
  • 消费者处理消息时:
    • 消费者接收消息后还未处理,MQ突然宕机
    • 消息接收后处理过程中抛出异常

要从三个方面保证MQ的可靠性:

  • 确保生产者一定把消息发送到MQ
  • 确保MQ不会将消息弄丢
  • 确保消费者一定要处理消息

解决流程与兜底方案

第一个方面:确保生产者一定把消息发送到MQ

确保生产者将消息发送到MQ有两种机制分别是:1.生产者重试机制、2.生产者确认机制

1.生产者重试机制

发生原因:

第一种情况,就是生产者发送消息时,出现了网络故障,导致与MQ的连接中断。

实现:

使用SpringAMQP提供的消息发送时的重试机制。即:当RabbitTemplate与MQ断网后等情况下,连接超时后,多次重试。

application.yaml文件配置

spring:rabbitmq:connection-timeout: 1s # 设置MQ的连接超时时间template:retry:enabled: true # 开启超时重试机制initial-interval: 1000ms # 失败后的初始等待时间multiplier: 1 # 失败后下次的等待时长倍数,下次等待时长 = initial-interval * multipliermax-attempts: 3 # 最大重试次数

:::info
注意事项:

在网络不稳定的情况下,利用重试机制可以有效提高消息发送的成功率。但是SpringAMQP提供的重试机制是阻塞式的重试,也就是说多次重试等待的过程中,当前线程是被阻塞的。

在项目中如果对于该业务性能有要求,建议禁用重试机制。如果一定要使用,请合理配置等待时长和重试次数,当然也可以考虑使用异步线程来执行发送消息的代码。

:::

2.生产者确认机制

发生原因:

一般情况下生产者与MQ之间的网络没有问题,基本就不会出现消息丢失的问题,但在少数情况下也有可能出现消息发送到MQ之后消息丢失的问题。

少数情况:

  • 在MQ的内部处理消息的进程出现了问题
  • 生产者发送消息到达MQ之后没有找到对应的交换机(Exchange)
  • 生产者发送消息到达MQ的交换机(Exchange)后,没有找到合适的Queue,因此无法进行路由

方案:

RabbitMQ的生产者消息确认机制包括有:Publisher ConfirmPublisher Return两种。开启消息确认机制情况下,当生产者发送消息给MQ后,MQ会根据消息处理的情况返回不同的回执

如图所示:

图解如下:

  • 当消息投递到MQ,但是路由失败时,通过Publisher Return返回异常信息,同时返回ack的确认信息,代表投递成功
  • 临时消息投递到了MQ,并且入队成功,返回ACK,告知投递成功
  • 持久消息投递到了MQ,并且入队完成持久化,返回ACK ,告知投递成功
  • 其它情况都会返回NACK,告知投递失败

其中acknack属于Publisher Confirm机制,ack是投递成功;nack是投递失败。而return则属于Publisher Return机制。

实现:

**在application.yaml**中添加配置,开启生产者确认:

spring:rabbitmq:publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型publisher-returns: true # 开启publisher return机制

publisher-confirm-type有三种模式可选分别是:

  • none:关闭confirm机制,
    • 优点:性能高。
    • 缺点:无法保证消息送达,可能丢失消息。
  • simple:同步阻塞等待MQ的回执( 同步阻塞等待确认 ),会阻塞当前线程直到收到 confirm。
    • 优点: 实现简单 。
    • 缺点: 性能差,吞吐量低
  • correlated:MQ异步回调返回回执( 异步回调确认 )
    • 优点**:** 性能更好,推荐使用
    • 缺点**:** 实现略复杂,需要维护消息状态和回调处理

一般推荐使用:correlated机制,回调机制。

定义ReturnCallback

每个RabbitTemplate只能配置一个ReturnCallback,因此可以在配置类中统一设置。在publisher模块定义一个配置类:

package com.publisher.config;import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;@Slf4j
@AllArgsConstructor
@Configuration
public class MqConfig {private final RabbitTemplate rabbitTemplate;@PostConstructpublic void init(){rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returned) {log.error("触发return callback,");log.debug("exchange: {}", returned.getExchange());log.debug("routingKey: {}", returned.getRoutingKey());log.debug("message: {}", returned.getMessage());log.debug("replyCode: {}", returned.getReplyCode());log.debug("replyText: {}", returned.getReplyText());}});}
}

定义ConfirmCallback

由于每个消息发送时的处理逻辑不一定相同,因此ConfirmCallback需要在每次发消息时定义。具体来说,是在调用RabbitTemplate中的convertAndSend方法时,多传递一个参数:

CorrelationData中包含两个核心的东西:

  • id:消息的唯一标示,MQ对不同的消息的回执以此做判断,避免混淆
  • SettableListenableFuture:回执结果的Future对象

将来MQ的回执就会通过这个Future来返回,提前给CorrelationData中的Future添加回调函数来处理消息回执:

新建一个测试,向系统自带的交换机发送消息,并且添加ConfirmCallback

@Test
void testPublisherConfirm() {// 1.创建CorrelationDataCorrelationData cd = new CorrelationData();// 2.给Future添加ConfirmCallbackcd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {@Overridepublic void onFailure(Throwable ex) {// 2.1.Future发生异常时的处理逻辑,基本不会触发log.error("send message fail", ex);}@Overridepublic void onSuccess(CorrelationData.Confirm result) {// 2.2.Future接收到回执的处理逻辑,参数中的result就是回执内容if(result.isAck()){ // result.isAck(),boolean类型,true代表ack回执,false 代表 nack回执log.debug("发送消息成功,收到 ack!");}else{ // result.getReason(),String类型,返回nack时的异常描述log.error("发送消息失败,收到 nack, reason : {}", result.getReason());}}});// 3.发送消息rabbitTemplate.convertAndSend("hmall.direct", "q", "hello", cd);
}

执行结果如下:

可以看到,由于传递的RoutingKey是错误的,路由失败后,触发了return callback,同时也收到了ack。

当修改为正确的RoutingKey以后,就不会触发return callback了,只收到ack。

而如果连交换机都是错误的,则只会收到nack。

:::info
注意事项:

  • 开启生产者确认比较消耗MQ性能,一般不建议开启。
  • 路由失败:一般是因为RoutingKey错误导致,往往是编程导致
  • 交换机名称错误:同样是编程错误导致
  • MQ内部故障:这种需要处理,但概率往往较低。因此只有对消息可靠性要求非常高的业务才需要开启,而且仅仅需要开启ConfirmCallback处理nack就可以了。

:::


第二个方面:确保MQ不会将消息丢失

可能出现的问题:

消息在生产者发送到达MQ之后,MQ不能及时进行保存就有可能会导致消息丢失。

数据持久化

为了提升性能,默认MQ的数据都是在内存存储的临时数据,重启后就会消失。为了保证数据的可靠性,必须配置数据持久化

数据持久化方案有:

  • 交换机持久化
  • 队列持久化
  • 消息持久化
交换机持久化

控制台的Exchanges页面,添加交换机时配置交换机的Durability参数:

设置为Durable就是持久化模式,Transient就是临时模式。

2.队列持久化

在控制台的Queues页面,添加队列时,同样可以配置队列的Durability参数:

3.消息持久化

控制台发送消息的时候,可以添加很多参数,而消息的持久化是要配置一个properties

:::info
说明:在开启持久化机制以后,如果同时还开启了生产者确认,那么MQ会在消息持久化以后才发送ACK回执,进一步确保消息的可靠性。

不过出于性能考虑,为了减少IO次数,发送到MQ的消息并不是逐条持久化到数据库的,而是每隔一段时间批量持久化。一般间隔在100毫秒左右,这就会导致ACK有一定的延迟,因此建议生产者确认全部采用异步方式。

:::

LazyQueue

可能出现的情况:

RabbitMQ默认将接收到的信息保存在内存中以降低消息收发的延迟。在某些特殊情况下会导致消息积压:

  • 消费者宕机或出现网络故障
  • 消息发送量激增,超过了消费者处理速度
  • 消费者处理业务发生阻塞

出现消息堆积问题,RabbitMQ的内存占用就会越来越高,直到触发内存预警上限。此时RabbitMQ会将内存消息刷到磁盘上,这个行为成为PageOut. PageOut会耗费一段时间,并且会阻塞队列进程。因此在这个过程中RabbitMQ不会再处理新的消息,生产者的所有请求都会被阻塞。

配置Lazy Queue(惰性队列)作用:

  • MQ接收到消息后将消息直接存入磁盘,不存入内存从而减小内存的占用,避免消息积压而导致的性能下降。
  • 消费者需要消费消息时才会从磁盘中读取并加载到内存(懒加载)
  • 支持数百万条消息的存储
控制台配置Lazy模式

添加队列的时候,添加x-queue-mod=lazy参数即可设置队列为Lazy模式:

SpringAMQP代码声明Lazy模式

SpringAMQP声明队列的时候,添加x-queue-mod=lazy参数也可设置队列为Lazy模式:

@Bean
public Queue lazyQueue(){return QueueBuilder.durable("lazy.queue").lazy() // 开启Lazy模式.build();
}

基于注解来声明队列并设置为Lazy模式:

@RabbitListener(queuesToDeclare = @Queue(name = "lazy.queue",durable = "true",arguments = @Argument(name = "x-queue-mode", value = "lazy")
))
public void listenLazyQueue(String msg){log.info("接收到 lazy.queue的消息:{}", msg);
}
更新已有队列为lazy模式

对于已经存在的队列,也可以配置为lazy模式,但是要通过设置policy实现。

可以基于命令行设置policy:

rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues

命令解读:

  • rabbitmqctl :RabbitMQ的命令行工具
  • set_policy :添加一个策略
  • Lazy :策略名称,可以自定义
  • "^lazy-queue$" :用正则表达式匹配队列的名字
  • '{"queue-mode":"lazy"}' :设置队列模式为lazy模式
  • --apply-to queues:策略的作用对象,是所有的队列

也可以在控制台配置policy,进入在控制台的Admin页面,点击Policies,即可添加配置:

第三方面.确保消费者一定要处理消息

**可能出现的情况:**RabbitMQ发送消息给消费者后,消息不一定被消费者正确消费可能出现的故障:

  • 消息投递的过程中出现了网络故障
  • 消费者接收到消息后突然宕机
  • 消费者接收到消息后,因处理不当导致异常

这时候RabbitMQ就需要知道消费者的处理状态,消息处理失败时重新投递消息。

消费者确认机制(Consumer Acknowledgement

当消费者处理消息结束后,向RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状态。回执有三种可选值:

  • ack:成功处理消息,RabbitMQ从队列中删除该消息
  • nack:消息处理失败,RabbitMQ需要再次投递消息
  • reject:消息处理失败并拒绝该消息,RabbitMQ从队列中删除该消息

:::info
注意:

reject方式用的较少,除非是消息格式有问题,那就是开发问题了。因此大多数情况下我们需要将消息处理的代码通过try catch机制捕获,消息处理成功时返回ack,处理失败时返回nack.

:::

SpringAMQP实现:

配置文件:

spring:rabbitmq:listener:simple:acknowledge-mode: none # 不做处理

有三种处理模式:

  • **none**:不处理。即消息投递给消费者后立刻ack,消息会立刻从MQ删除。非常不安全,不建议使用
  • **manual**:手动模式。需要自己在业务代码中调用api,发送ackreject,存在业务入侵,但更灵活
  • **auto**:自动模式。SpringAMQP利用AOP对我们的消息处理逻辑做了环绕增强,当业务正常执行时则自动返回ack. 当业务出现异常时,根据异常判断返回不同结果:
    • 如果是业务异常,会自动返回nack,MQ重新发送消息;
    • 如果是消息处理或校验异常,自动返回reject;

失败重试机制

问题:

当消费者出现异常后,消息会不断requeue(重入队)到队列,再重新发送给消费者。如果消费者再次执行依然出错,消息会再次requeue到队列,再次投递,直到消息处理成功为止。

极端情况就是消费者一直无法执行成功,那么消息requeue就会无限循环,导致mq的消息处理飙升,给CPU和内存带来较大的压力。

解决方案:

开启消费者重试机制:在消费者出现异常时利用本地重试,而不是无限制的requeue到mq队列。

application.yml文件,添加内容:

spring:rabbitmq:listener:simple:retry:enabled: true # 开启消费者失败重试initial-interval: 1000ms # 初识的失败等待时长为1秒multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: 3 # 最大重试次数stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false

:::info
注意事项:

  • 开启本地重试时,消息处理过程中抛出异常,不会requeue到队列,而是在消费者本地重试
  • 重试达到最大次数后,Spring会返回reject,消息会被丢弃在某些对于消息可靠性要求较高的业务场景下,显然不太合适,需要结合失败处理策略进行处理。

:::

失败处理策略:

Spring允们自定义重试次数耗尽后的消息处理策略,这个策略是由MessageRecovery接口来定义的,有3个不同实现:

  • RejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢弃消息。默认就是这种方式
  • ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入队
  • RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机

优雅的一种处理方案是RepublishMessageRecoverer,失败后将消息投递到一个指定的,专门存放异常消息的队列,后续由人工集中处理。

示例代码:

1.consumer服务中定义处理失败消息的交换机和队列

public class ErrorMessageConfig {//定义处理失败消息的交换机@Beanpublic DirectExchange errorMessageExchange(){return new DirectExchange("error.direct");}//定义处理失败消息的队列@Beanpublic Queue errorQueue(){return new Queue("error.queue", true);}@Beanpublic Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with("error");}//关联队列和交换机@Beanpublic MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");}
}

当出现失败消息时可以在控制台查看并在后续进行处理:

业务幂等性

幂等性指的是:指同一个业务,执行一次或多次对业务状态的影响是一致的。

但数据的更新往往不是幂等的,如果重复执行可能造成不一样的后果。比如:

  • 取消订单,恢复库存的业务。如果多次恢复就会出现库存重复增加的情况
  • 退款业务。重复退款对商家而言会有经济损失。

可能出现重复执行的情况:

  • 页面卡顿时频繁刷新导致表单重复提交
  • 服务间调用的重试
  • MQ消息的重复投递

唯一消息id:

  1. 每一条消息都生成一个唯一的id,与消息一起投递给消费者。
  2. 消费者接收到消息后处理自己的业务,业务处理成功后将消息ID保存到数据库
  3. 如果下次又收到相同消息,去数据库查询判断是否存在,存在则为重复消息放弃处理。

实现:

SpringAMQP的MessageConverter自带了MessageID的功能

以Jackson的消息转换器为例:

@Bean
public MessageConverter messageConverter(){// 1.定义消息转换器Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();// 2.配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息jjmc.setCreateMessageIds(true);return jjmc;
}

业务判断:

业务判断就是基于业务本身的逻辑或状态来判断是否是重复的请求或消息,不同的业务场景判断的思路也不一样。

支付修改订单的业务为例,markOrderPaySuccess方法:

@Override
public void markOrderPaySuccess(Long orderId) {
// 1.查询订单
Order old = getById(orderId);
// 2.判断订单状态
if (old == null || old.getStatus() != 1) {// 订单不存在或者订单状态不是1,放弃处理return;
}
// 3.尝试更新订单
Order order = new Order();
order.setId(orderId);
order.setStatus(2);
order.setPayTime(LocalDateTime.now());
updateById(order);
}

优化合并:

@Override
public void markOrderPaySuccess(Long orderId) {lambdaUpdate().set(Order::getStatus, 2).set(Order::getPayTime, LocalDateTime.now()).eq(Order::getId, orderId).eq(Order::getStatus, 1).update();//相当于这样的SQL语句// UPDATE `order` SET status = ? , pay_time = ? WHERE id = ? AND status = 1}

兜底方案

**最终实现目标:**尽管MQ通知失败也要保证订单的支付状态一致。

实现:

通过主动查询保证订单的一致性

流程:

色线圈起来的部分就是MQ通知失败后的兜底处理方案,由交易服务自己主动去查询支付状态。

利用定时任务定期查询,例如每隔20秒就查询一次,并判断支付状态。如果发现订单已经支付,则立刻更新订单状态为已支付即可。

总结:

保证MQ消息的可靠性:

保证MQ消息的可靠性,采用了生产者确认机制、消费者确认、消费者失败重试等策略,确保消息投递的可靠性

兜底方案:

设置了定时任务,这样即便MQ通知失败,还可以利用定时任务作为兜底方案。

相关文章:

MQ消息的不可靠性发生情况与解决方案

文章目录 问题&#xff1a;可能出现的情况&#xff1a; 解决流程与兜底方案第一个方面&#xff1a;确保生产者一定把消息发送到MQ1.生产者重试机制2.生产者确认机制 第二个方面&#xff1a;确保MQ不会将消息丢失数据持久化交换机持久化2.队列持久化3.消息持久化 LazyQueue控制台…...

线程池(五):线程池使用场景问题

线程池&#xff08;五&#xff09;&#xff1a;线程池使用场景问题 线程池&#xff08;五&#xff09;&#xff1a;线程池使用场景问题1 线程池使用场景CountDownLatch、Future1.1 CountDownLatch原理示例代码 1.2 案例一&#xff08;es数据批量导入&#xff09;需求分析实现步…...

第十六届蓝桥杯网安初赛wp

解题列表 根据提示一步一步走&#xff0c;经过猜测&#xff0c;测试出app.py 经过仔细研读代码&#xff0c;找到密钥 编写python代码拿到flag key secret_key9828 flagd9d1c4d9e0d6c29e9aad71696565d99bc8d892a8979ec7a69b9a6868a095c8d89dac91d19ba9716f63b5 newbytearray(…...

8.学习笔记-Maven进阶(P82-P89)

&#xff08;一&#xff09;Maven-08-配置文件加载属性 通过maven可以做版本的集中管理&#xff0c;所以能不能通过maven进行配置文件&#xff08;jdbc.properties&#xff09;的集中管理。 &#xff08;1&#xff09;resource-》jdbc.properties 可以识别$符号 因为只能…...

基于 IPMI + Kickstart + Jenkins 的 OS 自动化安装

Author&#xff1a;Arsen Date&#xff1a;2025/04/26 目录 环境要求实现步骤自定义 ISO安装 ipmitool安装 NFS定义 ks.cfg安装 HTTP编写 Pipeline 功能验证 环境要求 目标服务器支持 IPMI / Redfish 远程管理&#xff08;如 DELL iDRAC、HPE iLO、华为 iBMC&#xff09;&…...

Ubuntu20.04部署Ragflow(Docker方式)

Ubuntu20.04部署Ragflow&#xff08;Docker方式&#xff09; Ubuntu20.04 RagflowRunning RagflowRunning Ollama 由于写这篇博客的时候电脑还没装输入法&#xff0c;所以先用半吊子英文顶着了…关于最后运行ollama的部分可以无视&#xff0c;因为我修改了端口所以才需要这么运…...

【C++语法】类和对象(2)

4.类和对象&#xff08;2&#xff09; 文章目录 4.类和对象&#xff08;2&#xff09;类的六个默认成员函数(1)构造函数&#xff1a;构造函数特点含有缺省参数的构造函数构造函数特点&#xff08;续&#xff09;注意事项构造函数补充 前面总结了有关对象概念&#xff0c;对比 C…...

JDK 17 与 Spring Cloud Gateway 新特性实践指南

一、环境要求与版本选择 1. JDK 17 的必要性 最低版本要求&#xff1a;Spring Boot 3.x 及更高版本&#xff08;如 3.4&#xff09;强制要求 JDK 17&#xff0c;以支持 Java 新特性&#xff08;如密封类、模式匹配&#xff09;和性能优化。JDK 17 核心特性&#xff1a; 密封类…...

深入了解及掌握AppScan不同测试策略的区别

引言 在当今数字化时代,应用程序安全至关重要。IBM AppScan作为一款强大的应用安全测试工具,提供了多种测试策略以适应不同的测试场景和需求。理解这些测试策略的区别,能够帮助安全测试人员更精准地开展测试工作,发现应用程序中潜藏的安全漏洞。本文将结合实际案例,深入剖…...

【Linux】web服务器的部署和优化

目录 nginx的安装与启用--/usr/share/nginx/html默认发布目录 nginx的主配置文件--/etc/nginx/nginx_conf nginx的端口 nginx默认发布文件--index.html nginx默认发布目录 nginx的访问控制 基于IP地址的访问控制 基于用户认证的访问控制 nginx的虚拟主机--/etc/nginx/…...

20250426在ubuntu20.04.2系统上解决问题mkfs.exfat command not found

20250426在ubuntu20.04.2系统上解决问题mkfs.exfat command not found 2025/4/26 21:11 缘起&#xff0c;使用NanoPi NEO开发板&#xff0c;编译FriendlyCore系统&#xff0c;打包eMMC固件的时候报错。 ./build.sh emmc-img -pack sd-card image, used to write frie…...

IDE使用技巧与插件推荐

一、高效使用技巧 1. 快捷键与操作优化 VS Code: 快速导航:Ctrl+P(Windows/Linux)或Cmd+P(macOS)打开文件搜索,输入文件名快速定位。多光标编辑:按住Alt(Windows/Linux)或Option(macOS)点击多个位置,同时编辑多处代码。Zen 模式:Ctrl+K Z(Windows/Linux)或Cmd…...

防火墙规则配置错误导致的网络问题排查

# 防火墙规则配置错误导致的网络问题排查指南 防火墙规则配置错误是网络连接问题的常见原因之一。以下是一套系统的排查步骤和方法&#xff1a; ## 1. 初步症状确认 - **常见表现**&#xff1a; - 特定服务无法访问 - 网络连接时断时续 - 部分IP地址或端口无法通信 …...

线性代数(一些别的应该关注的点)

一、矩阵 矩阵运算&#xff1a;线性变换 缩放、平移、旋转 无所不能的矩阵 - 三维图形变换_哔哩哔哩_bilibili...

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

路由器重分发&#xff08;静态路由OSPF动态路由RIP动态路由&#xff09; 开通端口并配置IP地址 OSPF路由 R1 Router>en Router#conf t Router(config)#int g0/0 Router(config-if)#no shut Router(config-if)#no shutdown Router(config-if)#ip add 192.168.10.254 255.…...

2.3java运算符

运算符 1. 算术运算符 算术运算符用于执行基本的数学运算&#xff0c;像加、减、乘、除等。 运算符描述示例加法int a 5 3; // a 的值为 8-减法int b 5 - 3; // b 的值为 2*乘法int c 5 * 3; // c 的值为 15/除法int d 6 / 3; // d 的值为 2%取模&#xff08;取余&…...

元数据驱动的 AI 开发:从数据目录到模型训练自动化

元数据驱动的 AI 开发&#xff1a;从数据目录到模型训练自动化 一、引言 在人工智能技术蓬勃发展的当今时代&#xff0c;AI 开发已成为各行业实现创新的核心驱动力。然而&#xff0c;数据规模爆炸式增长、类型复杂多样、来源分散等问题&#xff0c;导致数据管理混乱、模型训练…...

从OpenAI收购实时数据引擎揭示AI数据库进化方向

第一章&#xff1a;一场技术并购背后的“数据战争” 1.1 OpenAI为何盯上Rockset&#xff1f; 当OpenAI宣布收购Rockset时&#xff0c;数据库圈层炸开了锅。这家成立于2016年的公司&#xff0c;其创始人团队堪称“数据库界梦之队”&#xff1a;CTO Dhruba Borthakur曾主导Face…...

Linux0.11内存管理:相关代码

ch13_2 源码分析 boot/head.s 页表初始化&#xff1a; 目标&#xff1a;初始化分页机制&#xff0c;将线性地址空间映射到物理内存&#xff08;前 16MB&#xff09;&#xff0c;为保护模式下的内存管理做准备。核心流程 分配页目录表和页表的物理内存空间&#xff08;通过 .…...

ShaderToy学习笔记 03.多个形状和旋转

1. 正方形和旋转 1.1. 正方形 要绘制一个正方形&#xff0c;我们需要定义一个点到正方形边界的距离函数。对于中心在原点的正方形&#xff0c;其数学表达式为&#xff1a; 对于一个点 p(x,y) 到正方形边界的距离函数可以表示为: d max(|x|, |y|) - r 其中: |x| 和 |y| 分…...

Arduino+ESP01S烧录

这种办法不使用与ThonnyMircopython 前言 这里我们使用烧录器烧录&#xff0c;淘宝十几块钱一个的东西&#xff0c;ESP01S做一个WIFI继电器还是蛮有用的&#xff0c;就是烧录起来不太方便&#xff0c;传统的办法接线麻烦&#xff0c;需多次上电&#xff0c;也可能因为电源问题…...

什么是Lua模块?你会如何使用NGINX的Lua模块来定制请求处理流程?

大家好&#xff0c;我是锋哥。今天分享关于【什么是Lua模块&#xff1f;你会如何使用NGINX的Lua模块来定制请求处理流程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 什么是Lua模块&#xff1f;你会如何使用NGINX的Lua模块来定制请求处理流程&#xff1f; 1000道 互联…...

小白自学python第三天

学习python第三天 一、函数 1、函数介绍 函数就是组织好的&#xff0c;可重复使用的&#xff0c;用以实现特定功能的代码块。 现在我们现在需要统计多个字符串长度并且不考虑使用内置函数&#xff0c;你会怎么做&#xff1f;我们先用一种原始人办法看看吧&#xff1a; str…...

【CF】Day44——Codeforces Round 908 (Div. 2) C + Codeforces Round 1020 (Div. 3) DE

C. Anonymous Informant 题目&#xff1a; 思路&#xff1a; 比这场的D难&#xff0c;虽然也不是很难 一个很容易想到的就是由当前状态推出初始状态&#xff0c;那么怎么推呢&#xff1f; 一个性质就是如果对于某一个 x 它可以执行左移操作的话&#xff0c;那么它一定会到数组…...

深入理解HashMap:Hash冲突的解决机制

引言 HashMap 是 Java 集合框架中最常用的数据结构之一&#xff0c;它通过键值对的形式存储数据&#xff0c;并利用哈希算法实现高效的插入、删除和查询操作。然而&#xff0c;在实际使用中&#xff0c;由于哈希函数的有限性和哈希桶数量的限制&#xff0c;不可避免地会出现 哈…...

Datawhale AI春训营二期---使用AI实现老人的点餐效果(关于task2的相关思考)

文章目录 1.多次测试的结果2.分数是如何提高的3.关于上分点拨4.关于task2的收获 1.多次测试的结果 第一次和第二次的&#xff0c;都是使用的baseline: 第三次的&#xff1a; 2.分数是如何提高的 之前的几次都是通过这个baseline进行运行的&#xff0c;然后今天是了解了一下这…...

摩尔投票法详细介绍

原理 摩尔投票法&#xff08;Boyer-Moore Voting Algorithm&#xff09;是一种用于在存在多数元素的数组中&#xff0c;高效找出出现次数超过数组长度一半的元素的算法。其核心思想是通过元素抵消策略&#xff0c;逐步缩小候选范围&#xff0c;最终确定多数元素。 核心假设&a…...

DP之书架

现按一定顺序给出所有要放置于书架上的书&#xff0c;共有 n 本&#xff0c;第 i 本书有一个长度 hi​。 书架有若干层&#xff0c;层与层之间的宽度不一定相等&#xff0c;但是一层的宽度不能小于其上所摆放的任何一本书的长度。同时&#xff0c;每层上的书的长度之和不能超过…...

Python Cookbook-6.11 缓存环的实现

任务 你想定义一个固定尺寸的缓存&#xff0c;当它被填满时&#xff0c;新加入的元素会覆盖第一个(最老的)元素。这种数据结构在存储日志和历史信息时非常有用。 解决方案 当缓存填满时&#xff0c;本节解决方案及时地修改了缓存对象&#xff0c;使其从未填满的缓存类变成了…...

计算机网络基本概念

层次名称主要功能第七层应用层直接面向用户&#xff0c;提供应用服务&#xff08;如浏览网页、发邮件&#xff09;第六层表示层处理数据格式、加密解密、压缩解压第五层会话层建立、管理、终止会话&#xff08;连接&#xff09;第四层传输层提供端到端的数据传输&#xff08;如…...

Eigen线性代数求解器(分解类)

1. 核心分解类概览 Eigen 提供多种矩阵分解方法&#xff0c;适用于不同矩阵类型&#xff08;稠密/稀疏、正定/非正定等&#xff09;&#xff1a; 分解类适用矩阵类型分解形式典型应用场景PartialPivLU方阵&#xff08;可逆&#xff09;APLUAPLU通用线性方程组求解FullPivLU任…...

【Android】四大组件之Service

目录 一、什么是Service 二、启停 Service 三、绑定 Service 四、前台服务 五、远程服务扩展 六、服务保活 七、服务启动方法混用 你可以把Service想象成一个“后台默默打工的工人”。它没有UI界面&#xff0c;默默地在后台干活&#xff0c;比如播放音乐、下载文件、处理…...

VO包装类和实体类分别是什么?区别是什么?

VO包装类和实体类 1. 实体类&#xff08;Entity Class&#xff09;是什么&#xff1f;2. VO包装类&#xff08;Value Object Class&#xff09;是什么&#xff1f;3. VO包装类和实体类的区别4. 实际应用中的区别5. 举例5.1. 实体类&#xff08;Entity Class&#xff09;的定义与…...

如何创建一个C#项目(基于VS2022版)

一.先找到要保存项目的位置,新建一个文件夹 二.打开VisualStudio,选择创建新项目 三.选择模版: 选择操作语言和操作系统 这个是跨平台的 初学在windows系统上,可选择其他,下面这个是不带窗体模版 也可根据需要选择带窗体模版 点击下一步 填写项目名称,选择项目保存位置,填写解…...

RabbitMQ 四种交换机(Direct、Topic、Fanout、Headers)详解

本文是博主在梳理 RabbitMQ 知识的过程中&#xff0c;将所遇到和可能会遇到的基础知识记录下来&#xff0c;用作梳理 RabbitMQ 的整体架构和功能的线索文章&#xff0c;通过查找对应的知识能够快速的了解对应的知识而解决相应的问题。 文章目录 一、直连交换机&#xff08;Dire…...

聚合分销系统开发:短剧小说外卖网盘电商cpscpa系统

聚合分销系统是一种整合了多种分销项目和功能的综合性平台&#xff0c;其核心在于通过CPS&#xff08;按销售付费&#xff09;和CPA&#xff08;按行为付费&#xff09;两种模式&#xff0c;为推广者提供多样化的赚钱机会。以下是聚合分销系统的主要项目和功能&#xff1a; 一…...

【Flume 】Windows安装步骤、配置环境

&#x1f6e0; Flume 是什么&#xff1f; Apache Flume 是一个高效、可靠、可扩展的数据收集系统&#xff0c;通常用于收集日志、流数据&#xff0c;比如收集数据到 HDFS、Kafka 等。 虽然 Flume 本身是为 Linux 服务器设计的&#xff0c;但 在 Windows 本地也是能跑起来的&a…...

【信息系统项目管理师】高分论文:论质量管理和进度管理(智慧旅游平台建设项目)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划质量管理2、质量保证3、质量控制论文 2019年3月,我作为项目经理,参加了某市智慧旅游平台建设项目,负责项目的全面管理, 该项目以打造一流的国内外生态旅游城市为目标,旨在大数据云平台建设的基…...

一致性哈希详解:优雅地扩展分布式系统

引言 对于哈希算法&#xff0c;相信大家一定不会陌生。它经常被用在负载均衡、分库分表等场景中。例如&#xff0c;在进行分库分表时&#xff0c;我们可能初步根据业务分析&#xff0c;确定 128 张表足以满足当前的数据量需求。此时&#xff0c;当需要插入或查询一条记录时&am…...

pytest 技术总结

目录 一 pytest的安装&#xff1a; 二 pytest有三种启动方式&#xff1a; 三 用例规则&#xff1a; 四 配置框架&#xff1a; 一 pytest的安装&#xff1a; pip install pytest # 安装 pip install pytest -U # 升级到最新版 二 pytest有三种启动方式&#xff1a; 1…...

数据库MySQL学习——day5(总结与复习实践)

文章目录 1、复习总结1.1. 数据库基础1.2. 表操作1.3. 数据操作1.4. 更新与删除 2、实践任务&#xff1a;创建学生管理系统数据库2.1. 数据库设计2.2. 创建表的SQL语句2.3. 插入示例数据2.4. 查询与数据操作示例 3、调试与练习4、 今日小结 1、复习总结 1.1. 数据库基础 数据…...

unity bug

发现一个奇怪的bug&#xff0c;就是某些unity版本打包apk时候不允许StreamingAssets里面有中文文件或者中文路径。比如下图这面这俩都是不行的。 解决方案&#xff1a;中文改为英文即可。 一般报错信息如下&#xff1a; > Configure project :launcher WARNING:The option s…...

苹果计划2026年底前实现美版iPhone“印度造”,以减轻关税及地缘政治风险

基于 6 个来源 据多家媒体报道&#xff0c;苹果公司计划在2026年底前&#xff0c;实现在印度组装销往美国的大部分或全部iPhone手机&#xff0c;以减轻关税和地缘政治紧张局势带来的风险。这一目标意味着苹果需将印度的iPhone产量增加一倍以上&#xff0c;凸显其供应链多元化战…...

新增Webhook通知功能,文档目录树展示性能优化,zyplayer-doc 2.5.1 发布啦!

zyplayer-doc是一款适合企业和个人使用的WIKI知识库管理工具&#xff0c;支持在线编辑富文本、Markdown、表格、Office文档、API接口、思维导图、Drawio以及任意的文本文件&#xff0c;支持基于知识库的AI问答&#xff0c;专为私有化部署而设计&#xff0c;最大程度上保证企业或…...

【量化交易笔记】17.多因子的线性回归模型策略

前言 上一篇介绍了 因子的评价和分析方法&#xff0c;让我知道如何判断该因子的作用&#xff0c;以及对最终结果的影响&#xff0c;其最大的问题&#xff0c;他只能评价和分析单因子&#xff0c;而对多个因子&#xff0c;不能直接加以评价。我们自然会想到&#xff0c;如果是多…...

五年经验Java开发如何破局创业

🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息文章目录 五年经验Java开发如何破局创业一、创业方向筛选与优劣势分析**方向1:技术教育/在线课程开发****方向2:企业级技术服务外包****方向3:技…...

定制一款国密浏览器(11):SM2算法的椭圆曲线参数定义

在国密算法中,SM2 算法是最复杂的,不仅是算法本身比较复杂,其应用场景也复杂。不管 SM2 算法本身有多复杂,作为开发者,我们需要知道的是 SM2 算法是建立在椭圆曲线算法(ECC)之上。关于 SM2 算法和椭圆曲线算法之间的关系,参考我之前的一篇文章: 解读国密非对称加密算…...

RAG技术与应用---0426

大语言模型>3.10 课程中会用到python 工具箱&#xff1a; faiss,modelscope,langchain,langchain_community&#xff0c;PyPDF2 1&#xff09;大模型应用开发的三种模式 提示词没多少工作量&#xff0c;微调又花费时间费用&#xff0c;RAG是很多公司招聘用来对LLM进行应用…...

STM32的开发环境介绍

目录 STM32软件环境 Keil软件在线安装 其他软件环境安装 STM32开发的几种方式 STM32寄存器版本和库函数版本 标准外设库的作用&#xff1a; STM32软件环境 STM32 的集成开发环境&#xff08;IDE&#xff09;&#xff1a;编辑编译软件 常见的环境&#xff1a; (1)KEIL&a…...

【生成式AI】从原理到实践的创造性革命

目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比 二、实战演示环境配置要求核心代码实现&#xff08;文生图&#xff09; 三、性能对比测试方法论量化数据对比结果分析 四、最佳实践推荐方…...