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

RabbitMQ可靠性进制

文章目录

    • 1.生产者可靠性
      • 生产者重连
      • 生产者确认
      • 小结
    • 2. MQ的可靠性
      • 数据持久化
      • LazyQueue
      • 小结
    • 3. 消费者的可靠性
      • 消费者确认机制
      • 消费者失败处理方案
      • 业务幂等性
        • 唯一消息ID
        • 业务判断
      • 兜底方案
        • 业务判断
      • 兜底方案


1.生产者可靠性

生产者重连

在某些场景下由于网络波动,可能就会出现客户端连接MQ失败的情况,,此时我们可以在Spring配置文件中开启连接失败后的重连机制:

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

需要注意的是,虽然这个重试机制在网络不稳定的时候可以有效提高消息的发送成功率。而SpringAMQP提供的重试机制是阻塞式的重试,也就是说这个操作并不是异步的会导致主线程被阻塞,从而影响业务性能。

如果对于业务性能有要求,建议禁用重试机制。如果非要使用,一定要合理配置等待时长和重试次数,或者采用异步线程来处理发送消息的代码

生产者确认

RabbitMQ提供了生产者消息确认机制,包括Publisher ConfirmPublisher Return两种,在MQ成功收到消息后会返回确认消息给生产者。而返回的结果又一下几种情况:

  • 消息投递到了MQ,但是路由失败,此时会通过Publisher Return返回路由异常原因,然后返回ACK,并return一个路由失败的消息
    • 路由失败一般不会出现,路由失败可能是这个路由并没有绑定队列,或者说代码写的有问题
    • 所以说路由失败这种情况只要开发配置和代码没有问题,几乎不可能出现
  • 第二种场景就是临时消息投递到了MQ,并且入队成功,返回ACK,告诉发送者消息投递成功
  • 第三种场景就是持久化消息投递到了MQ,并且消息持久化到磁盘后,才返回ACK告诉发送者消息投递成功

除了以上三种场景消息发送成功会返回ACK,其它的情况都会返回NACK,比如说持久化到磁盘失败了,内存满了导致内存丢失。

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

通过以上机制基本能保证消息发生成功,只要失败就进行重发

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码实现生产者确认机制:

在Spring配置文件中添加对应配置文件:

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

这里publisher-confirm-type有三种模式可选:

  • none:关闭confirm机制
  • simple:同步阻塞等待MQ的回执
  • correlated:MQ异步回调返回回执

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

定义ReturnCallback

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

@Configuration
@Slf4j
public class MqConfig implements ApplicationContextAware {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returnedMessage) {log.debug("收到return callback消息:exchange:{},code:{},replyText:{},returnMsg:{}",returnedMessage.getExchange(),returnedMessage.getReplyCode(),returnedMessage.getReplyText(),returnedMessage.getMessage());}});}
}

定义ConfirmCallback

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

@Test
void confirmCallback() throws InterruptedException {// 1.创建CorrelationDataCorrelationData correlationData = new CorrelationData();// 2. 给Future添加confirmCallbackcorrelationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {@Overridepublic void onFailure(Throwable ex) {// 该异常是Spring AMQP的异常,和RabbitMQ的无关log.error("future消息发送失败:{}",ex);}@Overridepublic void onSuccess(CorrelationData.Confirm result) {if (result.isAck()){log.debug("消息发送成功,收到确认ACK");} else {log.error("消息发送失败,收到NACK,原因: {}",result.getReason());}}});// 3. 发送消息rabbitTemplate.convertAndSend("test.direct", "red", "hello, confirm callback", correlationData);
}

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

  • id:消息的唯一标示,MQ对不同的消息的回执以此做判断,避免混淆(默认构造方法使用了UUID)

    public CorrelationData() {this.id = UUID.randomUUID().toString();
    }
    
  • SettableListenableFuture:回执结果的Future对象,利用回调函数异步处理确认消息

注意事项

开启生产者确认也是比价消耗MQ的性能的,一般也是不建议开启的,生产者确认消息主要有以下几种场景:

  • 一种是路由失败,一般是RoutingKey失败导致的,还有就是交换机名称错误,这也就是编码问题
  • MQ内部故障,这种场景出现概率比价低除非对消息可靠性要求较高的业务才需要开启,并且只要开启ConfirmCallback处理NACK就可以了

因为生产者确认机制需要额外的网络何系统资源开销,所以如果非要使用生产者确认机制,只需要开启Publisher Confirm机制,并且只是处理NACK消息,进行指定次数的重试,如果依然失败记录异常消息即可。

Publisher Return这种一般由于配置或者编码出现问题的根本不需要关心,因为路由出现问题一般是业务代码的问题

小结

如何保证生产发送消息的可靠性?

  1. 首先我们可以在配置文件中开启生产者重连机制,避免网络波动场景下客户端连接MQ失败
  2. 如果是其他原因导致的失败,RabbitMQ还支持生产者确认机制,接着开启生产者确认机制,根据返回的ACK和NAC来确认是否重发消息
  3. 通过以上手段基本可以保证生产者发送消息的可靠性
  4. 但是因为生产者重连和确认机制会增加网络和系统资源的开销,所以在大多数场景下无需开启确认和重连机制,除非对消息可靠性要求较高

2. MQ的可靠性

生产者在发送的消息到达MQ之后,如果MQ不能及时保存,也会导致消息丢失,所以MQ的可靠性我们也要非常关注。

  • 一旦MQ宕机,内存中的消息会丢失
  • 内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞

如果采用的是非持久化的消息(纯内存),当不断往MQ中发送消息,MQ的队列存储不下的时候就会发生PageOut,将存放不下的一部老消息存放到磁盘中,在PageOut的那一瞬间是无法处理消息的,也就是阻塞状态。可能就会导致消息堆积,影响性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据持久化

为了提升MQ的性能,默认情况MQ的数据都是在内存中临时存储的,只要一重启就会丢失,为了保证数据的可靠性就必须去配置数据持久化,持久化又包括:

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

如下图在创建队列的时候就能指定创建持久化队列

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在发送消息的时候也需要指定消息为持久化的消息,而SpringAMQP提供的发送消息的方法默认就是发送的持久化的消息。

使用持久化的消息,将每次发送的消息备份到磁盘中,过一段时间清空内存中已经持久化的消息,保证消息的一个安全性,也就说某一时刻内存和磁盘都会存在同一份消息,只是后续内存会做一个清空,在清空内存的时候会有一定的性能下降,但并不会出现像存内存那样的PageOut直接阻塞无法处理消息

LazyQueue

从RabbitMQ的3.6.0版本开始,就增加了Lazy Queues的模式,也就是惰性队列。惰性队列的特征如下:

  • 接收到消息后直接存入磁盘而非内存(内存中指保留最近的一部分消息)
  • 消费者要消费消息时才会从磁盘中读取并加载到内存(也就是懒加载)
  • 支持数百万条的消息存储

在3.12版本后,所有队列都是Lazy Queue模式,无法更改

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码配置Lazy模式

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

使用声明式注解

@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);
}

小结

RabbitMQ如何保证消息的可靠性

  1. 首先通过配置可以让交换机、队列、以及发送的消息都持久化。这样队列中的消息会持久化到磁盘,MQ重启消息依然存在。
  2. RabbitMQ在3.6版本引入了LazyQueue,并且在3.12版本后会称为队列的默认模式。LazyQueue会将所有消息都持久化。
  3. 开启持久化和生产者确认时, RabbitMQ只有在消息持久化完成后才会给生产者返回ACK回执

3. 消费者的可靠性

当RabbitMQ向消费者投递消息以后,需要知道消费者处理消息的状态如何,因为不能保证消息投递给消费者并不代表就一定被正确消费了,因为消费者也会出现很多的异常情况,比如说:

  • 消息在投递过程中出现了网络波动
  • 消费者收到了消息,但是消费者机器突然宕机了
  • 消费者接受到消息后,没有正确处理消息导致异常

除了上诉还有其他的异常情况,从而导致消息丢失,因此RabbitMQ还需要知道消费者的处理状态,消费者处理失败就可以进行重新投递消息

消费者确认机制

为了确认消费者是否成功处理消息,RabbitMQ提供了消费者确认机制(Consumer Acknowledgement)。即:当消费者处理消息结束后,应该向RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状态。回执有三种可选值:

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

一般使用reject这种方式情况比较少,消息处理失败比如说消息格式有问题啥的(消息转换异常),而这种情况一般使用try/chtch机制捕获,消息处理成功返回ACK,失败就返回nack。

由于消息回执的处理代码比较统一,因此SpringAMQP帮我们实现了消息确认。并允许我们通过配置文件设置ACK处理方式,有三种模式:

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

返回Reject的常见异常有:

Starting with version 1.3.2, the default ErrorHandler is now a ConditionalRejectingErrorHandler that rejects (and does not requeue) messages that fail with an irrecoverable error. Specifically, it rejects messages that fail with the following errors:

  • o.s.amqp…MessageConversionException: Can be thrown when converting the incoming message payload using a MessageConverter.
  • o.s.messaging…MessageConversionException: Can be thrown by the conversion service if additional conversion is required when mapping to a @RabbitListener method.
  • o.s.messaging…MethodArgumentNotValidException: Can be thrown if validation (for example, @Valid) is used in the listener and the validation fails.
  • o.s.messaging…MethodArgumentTypeMismatchException: Can be thrown if the inbound message was converted to a type that is not correct for the target method. For example, the parameter is declared as Message but Message is received.
  • java.lang.NoSuchMethodException: Added in version 1.6.3.
  • java.lang.ClassCastException: Added in version 1.6.3.

通过Spring的配置文件,可以配置SpringAMQP的ACK处理方式()

spring:rabbitmq:listener:simple:acknowledge-mode: auto # 自动ack

消费者失败处理方案

根据上诉的消费者处理机制,消费者出现异常后消息会不断重新进入到队列会哦只能,再次重新尝试发送给消费者,那么此时消费者再次消费消息又报错,消息又会重新入队,知道消息处理完成。

假设极端情况消费者就是无法处理该消息,那么消息就会无限循环,导致mq的消息处理表现造成不小的系统开销,影响系统性能。

不过出现这种极端情况的概率是非常低的,针对上诉情况Spring又为开发者提供了消费者失败重试机制,在消费者出现异常的时候利用本地重试,而不是不断的将消息发送到mq的队列中,

修改Spring的配置文件

spring:rabbitmq:listener:simple:retry:enabled: true # 开启消费者失败重试initial-interval: 1000ms # 初识的失败等待时长为1秒multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: 3 # 最大重试次数stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
  • 消费者在失败后消息没有重新回到MQ无限重新投递,而是在本地重试了3次
  • 本地重试3次以后,抛出了AmqpRejectAndDontRequeueException异常。查看RabbitMQ控制台,发现消息被删除了,说明最后SpringAMQP返回的是reject

结论:

  • 开启本地重试时,消息处理过程中抛出异常,不会requeue到队列,而是在消费者本地重试
  • 重试达到最大次数后,Spring会返回reject,消息会被丢弃

业务幂等性


在程序开发中业务幂等性指的是同一个业务,执行一次或者执行多次对业务状态的影响是一致的,也就执行一次或者多次是没有什么区别的。

比如:

  • 使用id来删除一条数据
  • 使用id来查询一条数据

数据的删除和查询操作通常都是幂等的,但是数据的更新操作往往不是幂等的,如果重复执行就可能出现不可预期的结果。比如说:

  • 取消订单:取消订单在恢复库存的时候,如果用户点击多次就可能出现库存重复增加的情况
  • 退款业务:重复的退款操作会对商家操作不小的损失。

所以在编写业务代码的时候要尽可能的避免业务被重复执行,然后实际业务中有很多业务场景都会被重复提交,比如说:

  • 用户网络卡顿频繁提交表单
  • 多个服务之间的调用重试
  • MQ的将同一条消息重复投递

因此,我们必须想办法保证消息处理的幂等性。这里给出两种方案:

  • 唯一消息ID
  • 业务状态判断
唯一消息ID

唯一消息ID其实就是个每一条消息一个UUID,然后将消息投递给消费者。

  1. 消费者接收到消息将消息处理后,将消息ID保存到数据库
  2. 如果下次又处理相同的消息,去数据库中查询是否存在即可

SpringAMQP的MessageConverter自带了MessageID的功能,我们只要开启这个功能即可。

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

该方案需要增加一个查和一个写数据库的操作对性能上有一定影响,还有一个需要保存消息ID也增加了耦合性,对业务有一定侵入

业务判断

我们还可以通过业务逻辑的判断来保证业务的幂等性。假设有一个支付场景,有已支付和未支付状态,在修改前判断是否已经支付,支付了就放弃本次操作。

通过MySQL的行锁即可实现,只有当订单为未支付的时候SQL才能执行修改成已支付状态

UPDATE `order` SET status = ? WHERE id = ? AND status = 1

兜底方案

MQ能保证99%的可能,但并不是百分之百,所以在某些时候我们可以做一些兜底方案,保证多个服务之间的订单状态一致。

比如说支付服务支付完成后MQ消息通知失败,就可以通过定时任务主动去查询支付状态来去更新订单状态


案需要增加一个查和一个写数据库的操作对性能上有一定影响,还有一个需要保存消息ID也增加了耦合性,对业务有一定侵入

业务判断

我们还可以通过业务逻辑的判断来保证业务的幂等性。假设有一个支付场景,有已支付和未支付状态,在修改前判断是否已经支付,支付了就放弃本次操作。

通过MySQL的行锁即可实现,只有当订单为未支付的时候SQL才能执行修改成已支付状态

UPDATE `order` SET status = ? WHERE id = ? AND status = 1

兜底方案

MQ能保证99%的可能,但并不是百分之百,所以在某些时候我们可以做一些兜底方案,保证多个服务之间的订单状态一致。

比如说支付服务支付完成后MQ消息通知失败,就可以通过定时任务主动去查询支付状态来去更新订单状态


相关文章:

RabbitMQ可靠性进制

文章目录 1.生产者可靠性生产者重连生产者确认小结 2. MQ的可靠性数据持久化LazyQueue小结 3. 消费者的可靠性消费者确认机制消费者失败处理方案业务幂等性唯一消息ID业务判断 兜底方案业务判断 兜底方案 1.生产者可靠性 生产者重连 在某些场景下由于网络波动&#xff0c;可能…...

版本控制器Git(5)

文章目录 前言一、理解标签二、创建标签三、操作标签四、多人协作场景一五、多人协作场景二总结 前言 本篇是最后一篇&#xff0c;主要介绍标签管理有关的内容 一、理解标签 标签定义&#xff1a;在Git中&#xff0c;标签&#xff08;tag&#xff09;是对某次提交&#xff08;c…...

Unity引擎架构介绍及代码示例

Unity是一款跨平台的游戏开发引擎&#xff0c;其强大的功能和灵活的架构使得它成为众多游戏开发者的首选。本文将详细介绍Unity引擎的架构&#xff0c;并通过代码示例展示其在实际开发中的应用。 一、Unity引擎架构概述 Unity引擎的架构可以分为以下几个主要部分&#xff1a; 1…...

【数据分析】读取文件

3. 读取指定列 针对只需要读取数据中的某一列或多列的情况&#xff0c;pd.read_csv()函数提供了一个参数&#xff1a;usecols&#xff0c;将包含对应的columns的列表传入该参数即可。 上面&#xff0c;我们学习了读取 "payment" 和 "items_count" 这…...

Dify使用部署与应用实践

最近在研究AI Agent&#xff0c;发现大家都在用Dify&#xff0c;但Dify部署起来总是面临各种问题&#xff0c;而且我在部署和应用测试过程中也都遇到了&#xff0c;因此记录如下&#xff0c;供大家参考。Dify总体来说比较灵活&#xff0c;扩展性比较强&#xff0c;适合基于它做…...

Java 大视界 -- 基于 Java 的大数据机器学习模型的迁移学习应用与实践(129)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

1.Windows+vscode+cline+MCP配置

文章目录 1.简介与资源2.在windows中安装vscode及Cline插件1. 安装vscode2. 安装Cline插件3. 配置大语言模型3. 配置MCP步骤(windows) 1.简介与资源 MCP官方开源仓库 MCP合集网站 参考视频 2.在windows中安装vscode及Cline插件 1. 安装vscode 2. 安装Cline插件 Cline插件…...

C#的字符串之String类与StringBuilder类区别于适用场景

一、分清楚值类型与引用类型 正确理解值类型与引用类型&#xff0c;可以更好的帮助软件开发人员写出性能更好且正确稳定运行的程序&#xff1a; C#值类型与引用类型区别 区别值类型引用类型定义所有继承自【System.ValueType】类型的都是值类型&#xff08;valueType继承自Sys…...

关于WPS的Excel点击单元格打开别的文档的两种方法的探究【为单元格添加超链接】

问题需求 目录和文件结构如下&#xff1a; E:\Dir_Level1 │ Level1.txt │ └─Dir_Level2│ Level2.txt│ master.xlsx│└─Dir_Level3Level3.txt现在要在master.xlsx点击单元格进而访问Level1.txt、Level2.txt、Level3.txt这些文件。 方法一&#xff1a;“单元格右键…...

conda的基本使用及pycharm里设置conda环境

创建conda环境 conda create --name your_env_name python3.8 把your_env_name换成实际的conda环境名称&#xff0c;python后边的根据自己的需要&#xff0c;选择python的版本。 激活conda环境 conda activate your_env_name 安装相关的包、库 conda install package_name …...

计算机网络-网络规划与设计

基本流程 需求分析—》通信规范分析—》逻辑网络设计—》物理网络设计—》实施阶段 需求分析&#xff1a; 确定需求&#xff0c;包括&#xff1a;业务需求、用户需求、应用需求、计算机平台需求、网络通信需求等。 产物&#xff1a;需求规范 通信规范分析&#xff1a; 现有…...

【QA】建造者模式在Qt有哪些应用

#设计模式 #Qt 一、QDomDocument&#xff08;XML 文档构建&#xff09; 模式角色&#xff1a; Builder&#xff1a;QDomDocument 本身Product&#xff1a;XML 文档对象Director&#xff1a;用户代码通过 QDomDocument 逐步构建文档结构 示例代码&#xff1a; QDomDocument…...

六种最新优化算法(TOC、MSO、AE、DOA、GOA、OX)求解多个无人机协同路径规划(可以自定义无人机数量及起始点),MATLAB代码

一、算法简介 &#xff08;一&#xff09;阿尔法进化&#xff08;Alpha Evolution&#xff0c;AE&#xff09;算法 阿尔法进化&#xff08;Alpha Evolution&#xff0c;AE&#xff09;算法是2024年提出的一种新型进化算法&#xff0c;其核心在于通过自适应基向量和随机步长的…...

练习-依依的询问最小值(前缀和差分)

问题描述 依依有个长度为 n 的序列 a&#xff0c;下标从 1 开始。 她有 m 次查询操作&#xff0c;每次她会查询下标区间在[li​,ri​] 的 a 中元素和。她想知道你可以重新排序序列 a&#xff0c;使得这 m 次查询的总和最小。 求你求出 m 次查询总和的最小值。 输入格式 第…...

ctfshow web刷题记录

RCE 第一题 eval代码执行 &#xff1a; 1、使用system 加通配符过滤 ?csystem("tac%20fl*") ; 2、反字节执行 xxx %20 echo 反字节 3、变量转移 重新定义一个变量 让他代替我们执行 4、伪协议玩法 ?cinclude$_GET[1]?>&1php://filter/readc…...

MySQL单表查询大全【SELECT】

山再高&#xff0c;往上攀&#xff0c;总能登顶&#xff1b;路再长&#xff0c;走下去&#xff0c;定能到达。 Mysql中Select 的用法 ------前言------【SELECT】0.【准备工作】0.1 创建一个库0.2 库中创建表0.3 表中加入一些数据 1.【查询全部】2.【查询指定列】2.1查询指定列…...

考研系列-408真题计算机网络篇(18-23)

写在前面 此文章是本人在备考过程中408真题计算机网络部分&#xff08;2018年-2023年&#xff09;的易错题及相应的知识点整理&#xff0c;后期复习也常常用到&#xff0c;对于知识提炼归纳理解起到了很大的作用&#xff0c;分享出来希望帮助到大家~ # 2018 1.停止-等待协议的…...

卷积神经网络(CNN)之 EfficientNet

在深度学习领域&#xff0c;模型的计算效率与性能之间的平衡一直是一个核心挑战。随着卷积神经网络&#xff08;CNN&#xff09;在图像分类、目标检测等任务中取得显著成果&#xff0c;模型的复杂度和计算需求也急剧增加。2019年&#xff0c;Google Research 提出的 EfficientN…...

【eNSP实战】将路由器配置为DHCP服务器

拓图 要求&#xff1a; 为 office100 和 office200 分别配置地址池 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.100.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 192.168.200.1 255.255.255.0 AR1路由器上创建office100地址池 [AR1…...

工程化与框架系列(35)--前端微服务架构实践

前端微服务架构实践 &#x1f3d7;️ 引言 随着前端应用规模的不断扩大&#xff0c;微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。 微服务架构概述 前端微服务架构主要包括以下方面&#xff1a; 应用拆分&#xf…...

Windows系统中安装Rust工具链方法

Windows系统中安装Rust工具链方法 在Windows上使用PowerShell的命令来下载rustup-init.exe文件。 此外&#xff0c;安装完成后&#xff0c;需要确保Rust的环境变量生效&#xff0c;可能需要重启终端或手动执行设置路径的命令。然后继续升级pip并安装tiktoken。 总结步骤应该是…...

Postman下载安装及简单入门

一&#xff0e;Postman简介 Postman是一款API测试工具&#xff0c;可以帮助开发、测试人员发送HTTP请求&#xff0c;与各种API进行交互&#xff0c;并分析响应 二&#xff0e;下载与安装 访问Postman官网&#xff08;https://www.postman.com/&#xff09;&#xff0c;下载适…...

vulnhub靶场之loly靶机

前言 挑战攻克该靶机30分钟 靶机&#xff1a;loly靶机&#xff0c;IP地址为192.168.10.11 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.6 靶机和攻击机都采用VMware虚拟机&#xff0c;都采用桥接网卡模式 文章涉及的靶机及工具&#xff0c;都可以自行访问官网或者项…...

原生微信小程序实现导航漫游(Tour)

效果&#xff1a; 小程序实现导航漫游 1、组件 miniprogram/components/tour/index.wxml <!--wxml--> <view class"guide" wx:if"{{showGuide}}"><view style"{{guideStyle}}" class"guide-box"><view class&quo…...

LLM论文笔记 25: Chain-of-Thought Reasoning without Prompting

Arxiv日期&#xff1a;2024.5.31机构&#xff1a;Google DeepMind 关键词 cot-decoding推理路径pretrain 核心结论 1. LLMs 不需要prompting就可以生成链式推理路径&#xff0c;prompting只是将这些能力显性化的一种手段 2. cot path 往往与更高的model confidence相关&…...

新型XCSSET恶意软件利用增强混淆技术攻击macOS用户

微软威胁情报团队发现了一种新型的XCSSET变种&#xff0c;这是一种复杂的模块化macOS恶意软件&#xff0c;能够感染Xcode项目&#xff0c;并在开发者构建这些项目时执行。 这是自2022年以来的首个已知XCSSET变种&#xff0c;采用了增强的混淆方法、更新的持久化机制以及新的感…...

Redis存数据就像存钱:RDB定期存款 vs AOF实时记账

Redis持久化 ◆ 核心概念1. ◆ 持久化全景图2. ◆ 生产环境黄金法则 ◆ RDB深度优化1. ◆ 生产配置精要2. ◆ 高级触发场景3. ◆ 故障应急方案 ◆ AOF深度解析1. ◆ 7.0版本革命性改进2. ◆ 同步策略深度测试3. ◆ 重写过程优化 ◆ 混合持久化实战1. ◆ 配置示例2. ◆ 数据恢复…...

[C++面试] 关于deque

一、入门 1、deque与vector的区别 deque的迭代器包含以下信息&#xff1a; 当前缓冲区指针&#xff08;current_buffer&#xff09;当前元素在缓冲区内的位置&#xff08;current&#xff09;中控器的位置&#xff08;map&#xff09; 每次移动迭代器时&#xff0c;需检查是…...

施磊老师c++(七)

STL组件 文章目录 STL组件1.整体学习内容2.vector容器3.deque和listdeque--双端队列容器list--链表容器 4.vector,deque,list对比主要内容面经问题 5.详解容器适配器--stack, queue, priority_queue容器适配器stack-栈queue-队列priority_queue-优先级队列总结 6.无序关联容器关…...

八股文——C 语言宏、`volatile`、`static`、动态内存管理、堆与栈的区别

文章目录 1. #&#xff08;字符串化操作符&#xff09;作用&#xff1a;示例&#xff1a; 2. ##&#xff08;符号连接操作符&#xff09;作用&#xff1a;示例1&#xff1a;动态生成变量名 3. volatile 关键字作用&#xff1a;示例&#xff1a; 4. static 关键字作用&#xff1…...