【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列
🔥个人主页: 中草药
🔥专栏:【中间件】企业级中间件剖析
一、消息确认机制
消费者确认机制确保消息被正确处理后才从队列中删除。如果消费者处理失败(如业务异常或宕机),Broker 会重新投递消息。
确认模式
1. 自动确认(autoAck=true
)
-
原理:
消息一旦被消费者接收(无论是否处理成功),立即自动确认并从队列删除。 -
风险:
若消费者在处理消息时崩溃或抛出异常,消息将永久丢失(因为已被确认删除)。 -
适用场景:
非关键业务,允许消息偶尔丢失(如日志采集、监控数据)。
2. 手动确认(autoAck=false
)
-
原理:
消费者在处理消息后,必须显式调用basicAck()
确认消息;若处理失败,调用basicNack()
或basicReject()
拒绝消息。 -
核心方法:
-
basicAck(deliveryTag, multiple)
:确认单条或批量消息。 -
basicNack(deliveryTag, multiple, requeue)
:拒绝消息,可选择是否重新入队。 -
basicReject(deliveryTag, requeue)
:拒绝单条消息(不支持批量)。
-
-
适用场景:
关键业务场景,要求消息必须可靠处理(如订单支付、库存扣减)。
手动确认(Spring Boot 示例)
spring:rabbitmq:listener:simple:acknowledge-mode: manual # 开启手动确认
Spring-AMQP对消息确认机制提供了三种策略
public enum AcknowledgeMode {NONE,MANUAL,AUTO;private AcknowledgeMode() {}public boolean isTransactionAllowed() {return this == AUTO || this == MANUAL;}public boolean isAutoAck() {return this == NONE;}public boolean isManual() {return this == MANUAL;}
}
AcknowledgeMode.NONE
这种模式下,消息一旦投递 给消费者,不管消费者是否成功处理了消息,RabbitMQ 就会自动确认消息,从 RabbitMQ 队列中移除消息。如果消费者处理消息失败,消息可能会丢失。
AcknowledgeMode.AUTO (默认)
这种模式下,消费者在消息处理成功时会自动确认消息,但如果处理过程中抛出了异常,则不会确认消息。
AcknowledgeMode.MANUAL
手动确认模式下,消费者必须在成功处理消息后显式调用 basicAck 方法来确认消息。如果消息未被确认,RabbitMQ 会认为消息尚未被成功处理,并且会在消费者可用时重新投递该消息,这种模式提高了消息处理的可靠性,因为即使消费者处理消息后失败,消息也不会丢失,而是可以被重新处理。
测试Demo
producer
@RestController
@RequestMapping("/producer")
public class ProducerController {@Autowiredprivate RabbitTemplate rabbitTemplate;@RequestMapping("/ack")public String ack(){rabbitTemplate.convertAndSend(Constants.ACK_EXCHANGE,"ack","ack mode test");return "ack mode test";}
}
listener
@Component
public class AckListener {@RabbitListener(queues = Constants.ACK_QUEUE)public void handleMessage(Message message, Channel channel) throws IOException {long deliveryTag = message.getMessageProperties().getDeliveryTag();try{System.out.printf("接收到消息: %s , deliveryTag = %d,\n",new String(message.getBody(),"UTF-8"),message.getMessageProperties().getDeliveryTag());System.out.println("业务逻辑处理1");int n=3/0;System.out.println("业务逻辑处理2");channel.basicAck(deliveryTag,false);}catch (Exception e) {channel.basicNack(deliveryTag,false,true);}}
}
二、持久化
RabbitMQ 的持久化是确保消息在服务器重启或异常崩溃后不丢失的核心机制。它通过将交换机、队列和消息内容写入磁盘来实现数据的持久保存。以下是持久化的详细说明及配置方法:
持久化的三个层级
交换机(Exchange)持久化
作用:确保交换机元数据在服务器重启后仍存在。
配置方式:声明交换机时设置 durable=true
。
代码示例(Spring Boot):
@Bean
public Exchange orderExchange() {return ExchangeBuilder.directExchange("order.exchange").durable(true) // 持久化交换机.build();
}
队列(Queue)持久化
作用:确保队列元数据(如队列名称、绑定关系)和消息的存储位置在重启后保留。
配置方式:声明队列时设置 durable=true
。
代码示例:
@Bean
public Queue orderQueue() {return QueueBuilder.durable("order.queue") // 持久化队列.deadLetterExchange("dlx.exchange") // 可选:绑定死信队列.build();
}
消息(Message)持久化
作用:将消息内容持久化到磁盘,防止服务器断电或重启导致消息丢失。
配置方式:发送消息时设置 deliveryMode=2
(持久化模式)。
代码示例:
rabbitTemplate.convertAndSend("order.exchange", "order.routingKey", message, msg -> {msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 消息持久化return msg;
});
消息是存储在队列之中的,所以消息持久化需要队列持久化+消息持久化 若仅仅是单独设置某一方的持久化,在MQ重启之后,消息仍然会发生丢失
三、发送方确认
以上所述内容分别对应三个环节的RabbitMQ的可靠性保证,前文已经对发布确认模式有了一个详细的介绍,这里我们进行补充
【RabbitMQ】RabbitMQ的核心概念与七大工作模式_mq的几种模式-CSDN博客
针对确保消息可靠发送到服务器,
a. 通过事务机制实现
b. 通过发送方确认 (publisher confirm) 机制实现
事务机制比较消耗性能,在实际工作中使用也不多,这里主要介绍 confirm 机制来实现发送方的确认。RabbitMQ为我们提供了两个方式来控制消息的可靠性传递
1、confirm确认模式
2、return退回模式
两种方法并不互斥,可以单独使用,也可以结合使用
Confirm确认模式
Producer 在发送消息的时候,对发送端设置一个 ConfirmCallback 的监听,无论消息是否到达 Exchange,这个监听都会被执行,如果 Exchange 成功收到,ACK (Acknowledge character,确认字符) 为 true,如果没收到消息,ACK 就为 false.
配置
测试代码
RabbitMQTemplate
@Configuration
public class RabbitTemplateConfig {@Bean(name = "rabbitTemplate")public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {return new RabbitTemplate(connectionFactory);}@Bean(name = "confirmRabbitTemplate")public RabbitTemplate confirmRabbitTemplate(ConnectionFactory connectionFactory) {//设置回调方法RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {@Overridepublic void confirm(CorrelationData correlationData, boolean b, String s) {System.out.println("执行了confirm方法");if(b){System.out.printf("接收到消息,消息ID:%s \n",correlationData==null?null:correlationData.getId());}else {System.out.printf("未接收到消息的ID:%s \n, cause: %s",correlationData==null?null:correlationData.getId(),s);//相应的业务逻辑处理}}});return rabbitTemplate;}}
@RestController
@RequestMapping("/producer")
public class ProducerController {@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate RabbitTemplate confirmRabbitTemplate;@RequestMapping("/pers")public String pers(){Message message=new Message("Persistent".getBytes(),new MessageProperties());message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);rabbitTemplate.convertAndSend(Constants.PERS_EXCHANGE,"pers","pers test");return "pers mode test";}@RequestMapping("/confirm")public String confirm(){CorrelationData correlationData=new CorrelationData("1");// rabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE,"confirm","confirm test",correlationData);//错误演示 Constants.CONFIRM_EXCHANGE+"1" 交换机不存在confirmRabbitTemplate.convertAndSend(Constants.CONFIRM_EXCHANGE+"1","confirm","confirm test",correlationData);return "confirm test";}
}
注意,回调方法只能设置一次,因此要使用配置的方法,如果将回调方法写在controller的方法内部,会致使出现以下问题
1、这种方式设置的confirmcallback会影响所有使用RabbitTemplate的方法
2、重复调用接口时,会提示错误
return退回模式
消息到达 Exchange 之后,会根据路由规则匹配,把消息放入 Queue 中。Exchange 到 Queue 的过程,如果一条消息无法被任何队列消费 (即没有队列与消息的路由键匹配或队列不存在等),可以选择把消息退回给发送者。消息退回给发送者时,我们可以设置一个返回回调方法,对消息进行处理。
首先同样进行配置(如图前文confirm一致)
设置返回的逻辑
@Configuration
public class RabbitTemplateConfig {@Bean(name = "rabbitTemplate")public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {return new RabbitTemplate(connectionFactory);}@Bean(name = "confirmRabbitTemplate")public RabbitTemplate confirmRabbitTemplate(ConnectionFactory connectionFactory) {//设置回调方法RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {@Overridepublic void confirm(CorrelationData correlationData, boolean b, String s) {System.out.println("执行了confirm方法");if(b){System.out.printf("接收到消息,消息ID:%s \n",correlationData==null?null:correlationData.getId());}else {System.out.printf("未接收到消息的ID:%s \n, cause: %s",correlationData==null?null:correlationData.getId(),s);//相应的业务逻辑处理}}});// rabbitTemplate.setReturnsCallback(returnedMessage -> {
// System.out.println("消息退回");
// });rabbitTemplate.setMandatory(true);//强制性rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returnedMessage) {System.out.println("消息退回"+returnedMessage);}});return rabbitTemplate;}
}
RabbitTemplate的setMandatory为true时,当有一条消息无法被任何队列消费,RabbitMQ应该会将消息返回该发送者,此时的ReturnCallBack方法就会被处罚
回调函数中有一个参数:ReturnedMessage
public class ReturnedMessage {//返回的消息对象,包含了消息体和消息属性private final Message message;//由Broker提供的回复码, 表⽰消息⽆法路由的原因. 通常是⼀个数字代码,每个数字代表不同
的含义. private final int replyCode;//⼀个⽂本字符串, 提供了⽆法路由消息的额外信息或错误描述.private final String replyText;//消息被发送到的交换机名称private final String exchange;//消息的路由键,即发送消息时指定的键private final String routingKey;
}
重试机制
在消息传递过程中,可能会遇到各种问题,如网络故障,服务不可用,资源不足等,这些问题可能导致消息处理失败,为了解决这些问题,RabbitMQ 提供了重试机制,允许消息在处理失败后重新发送.但如果是程序代码逻辑引起的错误,那么多次重试也是没有用的,可以设置重试次数。
注意:此重试策略的配置只有在acknowledge-mode 为 auto 时,才会生效
设置Listener消费信息
@Component
public class RetryListener {@RabbitListener(queues = Constants.RETRY_QUEUE)public void handleMessage(Message message) {System.out.printf("["+Constants.RETRY_QUEUE+"]接收到消息: %s ,deliverTag: %s \n",new String(message.getBody()),message.getMessageProperties().getDeliveryTag());int num=3/0;System.out.println("业务处理完成");}//手动确认
// @RabbitListener(queues = Constants.RETRY_QUEUE)
// public void handleMessage(Message message,Channel channel) throws Exception {
// System.out.printf("["+Constants.RETRY_QUEUE+"]接收到消息: %s ,deliverTag: %s \n",new String(message.getBody()),message.getMessageProperties().getDeliveryTag());
// try{
// int num=3/0;
// System.out.println("业务处理完成");
// channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);//是否批量 false
// }catch (Exception e){
// channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);//b-是否批量 b1-是否重新入队
// }
// }
}
此时会按照我们重试策略的配置来进行重试
使用重试机制时需要注意:
1.自动确认模式下: 程序逻辑异常,多次重试还是失败,消息就会被自动确认,那么消息就丢失了
2.手动确认模式下: 程序逻辑异常,多次重试消息依然处理失败,无法被确认,就一直是unacked的状态,导致消息积压
如何保证RabbitMQ消息的可靠传输
消息可能丢失的场景以及解决方案
生产者将消息发送到 broker 失败
a. 可能原因:网络问题等
b. 解决办法:发送方确认 - confirm 确认模式
消息在交换机中无法路由到指定队列
a. 可能原因:代码或者配置层面错误,导致消息路由失败
b. 解决办法:发送方确认 - return 模式
消息队列自身数据丢失
a. 可能原因:消息到达 RabbitMQ 之后,RabbitMQ Server 宕机导致消息丢失.
b. 解决办法:持久性,开启 RabbitMQ 持久化,就是消息写入之后会持久化到磁盘,如果 RabbitMQ 挂了,恢复之后会自动读取之前存储的数据.(极端情况下,RabbitMQ 还未持久化就挂了,可能导致少量数据丢失,这个概率极低,也可以通过集群的方式提高可靠性)
消费者异常,导致消息丢失
a. 可能原因:消息到达消费者,还没来得及消费,消费者宕机。消费者逻辑有问题.
b. 解决办法:消息确认,RabbitMQ 提供了消费者应答机制来使 RabbitMQ 能够感知到消费者是否消费成功消息。默认情况下消费者应答机制是自动应答的,可以开启手动确认,当消费者确认消费成功后才会删除消息,从而避免消息丢失。除此之外,也可以配置重试机制 , 当消息消费异常时,通过消息重试确保消息的可靠性
四、TTL
TTL(Time to live,过期时间),RabbitMQ可对消息和队列设置TTL,当消息打到大存活时间之后,还没有被消费就会被自动清除。
设置TTL的方法有很多种,这里不进行一一赘述
设置消息TTL
目前有两种方法可以设置消息的TTL.
一是设置队列的TTL,队列中所有消息都有相同的过期时间,二是对消息本身进行单独设置,每条消息的TTL可以不同.如果两种方法一起使用,则消息的TTL以两者之间较小的那个数值为准.
@RestController
@RequestMapping("/producer")
public class ProducerController {@Autowiredprivate RabbitTemplate rabbitTemplate;@RequestMapping("/ttl")public String ttl(){System.out.println("ttl ...");// MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
// @Override
// public Message postProcessMessage(Message message) throws AmqpException {
// message.getMessageProperties().setExpiration("10000"); //单位毫秒
// return message;
// }
// };//lambdarabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE,"ttl","ttl test",message -> {message.getMessageProperties().setExpiration("10000"); //单位毫秒return message;});return "ttl test";}}
即可通过队列观察到消息
设置队列TTL
@Configuration
public class RabbitMQConfig {//TTL//未设置TTL的队列@Bean("ttlQueue")public Queue ttlQueue() {return QueueBuilder.durable(Constants.TTL_QUEUE).build();}//设置ttl的队列@Bean("ttlQueue2")public Queue ttlQueue2() {return QueueBuilder.durable(Constants.TTL_QUEUE2).ttl(20000).build(); //设置队列的ttl为20s}@Bean("ttlExchange")public DirectExchange ttlExchange() {return ExchangeBuilder.directExchange(Constants.TTL_EXCHANGE).build();}@Bean("ttlBinding")public Binding ttlBinding(@Qualifier("ttlQueue") Queue ttlQueue,@Qualifier("ttlExchange") Exchange ttlExchange) {return BindingBuilder.bind(ttlQueue).to(ttlExchange).with("ttl").noargs();}@Bean("ttlBinding2")public Binding ttlBinding2(@Qualifier("ttlQueue2") Queue ttlQueue,@Qualifier("ttlExchange") Exchange ttlExchange) {return BindingBuilder.bind(ttlQueue).to(ttlExchange).with("ttl").noargs();}
}
为什么这两种方法处理的方式不一样?
因为设置队列过期时间,队列中已过期的消息肯定在队列头部,RabbitMO只要定期从队头开始扫描是否有过期的消息即可.
而设置消息TTL的方式,每条消息的过期时间不同,如果要删除所有过期消息需要扫描整个队列,所以不如等到此消息即将被消费时再判定是否过期,如果过期再进行删除即可.
五、死信队列
死信(Dead Letter)是消息队列中的一种特殊消息,它指的是那些无法被正常消费或处理的消息,死信队列用于存储这些死信消息
消息变为死信一般有以下几种情况
消息过期:消息在队列中存活的时间超过了设定的TTL
消息被拒绝:消费者在处理消息时,可能因为消息内容错误,处理逻辑异常等原因拒绝处理该消息(Basic.Reject/Basic.Nack).如果拒绝时指定不重新入队(requeue=false),消息也会成为死信
队列达到最大长度:当队列达到最大长度,无法再容纳新的消息时,新来的消息会被处理为死信.
代码示例
@Configuration
public class DLConfig {//正常@Bean("normalQueue")public Queue normalQueue(){return QueueBuilder.durable(Constants.NORMAL_QUEUE).deadLetterExchange(Constants.DL_EXCHANGE).deadLetterRoutingKey("dlx").maxLength(10).ttl(10000).build();}@Bean("normalExchange")public DirectExchange normalExchange(){return ExchangeBuilder.directExchange(Constants.NORMAL_EXCHANGE).build();}@Bean("bindingNormal")public Binding bindingNormal(@Qualifier("normalQueue") Queue normalQueue,@Qualifier("normalExchange") DirectExchange normalExchange){return BindingBuilder.bind(normalQueue).to(normalExchange).with("normal");}//死信@Bean("dlQueue")public Queue dlQueue(){return QueueBuilder.durable(Constants.DL_QUEUE).build();}@Bean("dlExchange")public DirectExchange dlExchange(){return ExchangeBuilder.directExchange(Constants.DL_EXCHANGE).build();}@Bean("bindingDl")public Binding bindingDl(@Qualifier("dlQueue") Queue dlQueue,@Qualifier("dlExchange") DirectExchange dlExchange){return BindingBuilder.bind(dlQueue).to(dlExchange).with("dlx");}
}
Listener
@Component
public class DLListener {@RabbitListener(queues = Constants.NORMAL_QUEUE)public void handleMessage(Message message, Channel channel) throws IOException {long deliveryTag = message.getMessageProperties().getDeliveryTag();try{System.out.printf("[normal.queue]接收到消息: %s , deliveryTag = %d,\n",new String(message.getBody(),"UTF-8"),message.getMessageProperties().getDeliveryTag());System.out.println("业务逻辑处理1");int n=3/0;System.out.println("业务逻辑处理2");channel.basicAck(deliveryTag,false);}catch (Exception e) {channel.basicNack(deliveryTag,false,false);}}@RabbitListener(queues = Constants.DL_QUEUE)public void dlHandleMessage(Message message, Channel channel) throws IOException {System.out.printf("[dl.queue]接收到消息: %s , deliveryTag = %d,\n",new String(message.getBody(),"UTF-8"),message.getMessageProperties().getDeliveryTag());}}
controller
@RestController
@RequestMapping("/producer")
public class ProducerController {@Autowiredprivate RabbitTemplate rabbitTemplate;@RequestMapping("/dl")public String dl(){System.out.println("dl ...");//发送普通消息//rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE,"normal","dl test");//测试队列长度for (int i = 0; i < 11; i++) {rabbitTemplate.convertAndSend(Constants.NORMAL_EXCHANGE,"normal","dl test "+i);}return "dl test";}}
即可进行测试
死信队列的应用场景
对于RabbitMQ来说,死信队列是一个非常有用的特性,它可以处理异常情况下,消息不能够被消费者正确消费而被置入死信队列中的情况,应用程序可以通过消费这个死信队列中的内容来分析当时所遇到的异常情况,进而可以改善和优化系统,
比如: 用户支付订单之后,支付系统会给订单系统返回当前订单的支付状态为了保证支付信息不丢失,需要使用到死信队列机制,当消息消费异常时,将消息投入到死信队列中,由订单系统的其他消费者来监听这个队列,并对数据进行处理(比如发送工单等,进行人工确认).场景的应用场景还有:
消息重试:将死信消息重新发送到原队列或另一个队列进行重试处理消息丢弃:直接丢弃这些无法处理的消息,以避免它们占用系统资源
日志收集:将死信消息作为日志收集起来,用于后续分析和问题定位
抛弃时间的人,时间也抛弃他。——莎士比亚
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸
相关文章:
【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列
🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、消息确认机制 消费者确认机制确保消息被正确处理后才从队列中删除。如果消费者处理失败(如业务异常或宕机),Broker 会重新投递消息…...
C# 正则表达式
C# 正则表达式 引言 正则表达式(Regular Expression,简称Regex)是一种用于处理字符串的强大工具,在编程领域有着广泛的应用。C# 作为一种流行的编程语言,也内置了对正则表达式的支持。本文将详细介绍 C# 中的正则表达…...
第十四届蓝桥杯省赛电子类单片机学习记录(客观题)
01.一个8位的DAC转换器,供电电压为3.3V,参考电压2.4V,其ILSB产生的输出电压增量是(D)V。 A. 0.0129 B. 0.0047 C. 0.0064 D. 0.0094 解析: ILSB(最低有效位)的电压增量计算公式…...
23种设计模式-桥接(Bridge)设计模式
桥接设计模式 🚩什么是桥接设计模式?🚩桥接设计模式的特点🚩桥接设计模式的结构🚩桥接设计模式的优缺点🚩桥接设计模式的Java实现🚩代码总结🚩总结 🚩什么是桥接设计模式…...
AI重塑视觉艺术:DeepSeek与蓝耘通义万相2.1的图生视频奇迹
云边有个稻草人-CSDN博客 近年来,深度学习、计算机视觉和生成模型在多个领域取得了突破性进展。其中,DeepSeek与蓝耘通义万相2.1图生视频的结合为图像生成与视频生成技术提供了新的发展方向。DeepSeek作为一个图像和视频生成的工具,能够利用深…...
mac怎么安装pycharm?
安装步骤:1、打开PyCharm官网,在官网首页点击“下载”按钮,选择“MacOS”版本进行下载;2、双击打开安装包,将PyCharm拖动到应用程序文件夹中;3、根据提示进行安装,在第一次运行PyCharm时&#x…...
HTML应用指南:利用POST请求获取城市肯德基门店位置信息
随着新零售业态的快速发展,门店位置信息的获取变得越来越重要。作为快餐服务行业的先锋,肯德基不仅在服务质量上持续领先,还积极构建广泛的门店网络,以支持其不断增长的用户群体。为了更好地理解和利用这些数据,本篇文…...
Java主流开发框架之请求响应常用注释
1.RestController 标记一个类为 REST 控制器,处理 HTTP 请求并直接返回数据(如 JSON/XML),而不是视图(如 HTML),一般是放在类的上边 RestController public class UserController {GetMapping…...
go的参数传递都是值传递,但切片需要注意
根据之前学习python和java的经验,每次学习一门新语言时,一定要搞清楚方法的参数传递是值传递,引用传递还是指针传递。 主要原因就是需要知道,某种类型的数据传递给某个方法后,方法里面对它的修改是否会影响到这个数据本…...
C++菜鸟教程 - 从入门到精通 第五节
一.各种排序 接下来,让我们开始学习排序! 1.选择排序 a.原理简介 选择排序(Selection Sort)是一种简单直观的排序算法。它的基本思想是每次从未排序的部分中选择最小(或最大)的元素,将其放到已排序部分的末尾ÿ…...
同一个局域网的话 如何访问另一台电脑的ip
在局域网内访问另一台电脑,可以通过以下几种常见的方法来实现: 直接通过IP地址访问: 首先,确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址,这可以通过在目标电脑上打开命令提示符(Windows系…...
[学习笔记]攻防世界-bug
打开场景,提示我们需要登陆 我们先注册一下 注册成功 我们登陆进去 我们点击Manage他提示我们admin才能进入 我们刷新抓包一下试试 Cookie里面除了PHPSESSID,多出来了一个user,看上去是md5加密的,我们尝试解密 这里尝试了好几个网…...
[250324] Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!| Wine 10.4 发布!
目录 Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!Wine 10.4 发布! Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft! 近日,Apache Kafka 4.0.0 正式发布!这是一个…...
【赵渝强老师】达梦数据库MPP集群的架构
为了支持海量数据存储和处理等方面的需求,为高端数据仓库提供解决方案,达梦数据库提供了大规模并行处理MPP架构,以极低的成本代价,提供高性能的并行计算。通过使用MPP可以解决以下问题: 需要较高的系统性能支持以支持…...
JWT 鉴权常见知识点及参考答案
JWT 鉴权常见知识点及参考答案 最近在 Go Web 项目当中使用到了 JWT 进行鉴权,因此通过这篇文章对 JWT 的原理及相关的知识点进行总结。 文章目录 JWT 鉴权常见知识点及参考答案JWT 签名算法的详细工作流程一. 签名的生成过程二. 签名的验证过程 1. 什么是 JWT&am…...
洛谷题单入门4-P5729 【深基5.例7】工艺品制作-python
输入格式 第一行三个正整数 w,x,h。 第二行一个正整数 q。 接下来 q 行,每行六个整数 输出格式 输出一个整数表示答案。 三维数组直接标记 class Solution:staticmethoddef oi_input():"""从标准输入读取数据"""w, x, h map(…...
【C语言】内存函数详解
个人主页 文章目录 🏠一、memcpy函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 🚀二、memmove函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 🎡三、memset函数1.函数形式以及功能介绍2.函数的使用 🎉四、memcmp1.函数形…...
使用Python开发自动驾驶技术:车道线检测模型
友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…...
HTTP代理的全面解读:什么是HTTP代理?HTTP代理的工作原理
在互联网大潮中,每一个请求和返回数据的背后,都离不开传输协议的支持,而HTTP协议无疑是最熟悉的网络通信基础之一。当我们谈到HTTP代理时,它不仅让浏览网络变得更高效,也为数据采集以及全球性远程任务提供了解决方案。…...
DeepSeek底层揭秘——deepEP
1. 什么是 deepEP? (1) 定义 deepEP (DeepSeek EndPoint) 是 DeepSeek 开源的一款高性能、低延迟的分布式通信库,专为大规模深度学习训练和推理场景设计。它旨在优化分布式计算环境中的通信效率,特别是在节点间数据交换、梯度同步、模型分发…...
内网渗透(CSMSF) 构建内网代理的全面指南:Cobalt Strike 与 Metasploit Framework 深度解析
目录 1. Cobalt Strike 在什么情况下会构建内网代理? 2. Cobalt Strike 构建内网代理的主要作用和目的是什么? 3. Cobalt Strike 如何构建内网代理?需要什么条件和参数? 条件 步骤 参数 4. Cobalt Strike 内网代理能获取什…...
【redis】哨兵:人工恢复主节点故障和哨兵自动恢复主节点故障
文章目录 基本概念人工恢复主节点故障操作流程 哨兵自动恢复主节点故障哨兵集 Redis 的主从复制模式下,⼀旦主节点由于故障不能提供服务,需要⼈⼯进⾏主从切换,同时⼤量的客⼾端需要被通知切换到新的主节点上,对于上了⼀定规模的应…...
【Go 】异常处理
1. Go 语言错误处理基础 Go 语言尽量避免使用异常,推荐使用 返回错误 让调用者处理。Go 语言标准库提供 error 接口:type error interface {Error() string }errors.New("错误信息") 创建错误对象。 package mainimport ("errors"…...
微软纳德拉最新一期访谈
萨提亚纳德拉: 微软的AGI计划与量子突破| 2025.2.20 【文章核心预览:】 1、纳德拉回应AI价格战:效率提升将重塑需求,但关键是能否带动GDP增长至10% 2、微软AI收入130亿美元,4年后目标1300亿,但提醒"…...
WebSocket接入SSL证书
目录 碎碎念解决方法创建 HTTPS WebSocket 服务器创建系统服务启动服务 碎碎念 在访问网站时,使用 HTTPS 非常重要。HTTPS 协议不仅可以确保数据传输的安全性,还可以防止中间人攻击和数据篡改等安全问题。任何没有 SSL 证书的内容都可能会被拒绝访问。因…...
蓝桥杯——嵌入式学习日记
因为lED和LCD共用PC8~PC15引脚,要通过锁存(LE)和(GPIOC->ODR)来避免LED和LCD引脚冲突 修改点: main.c中,GPIO初始化引脚后,LE(PD2引脚低电平锁存,退出透明模式&…...
第七课:Python基础排序算法与比较排序原理深度解析
比较排序算法是算法领域中的经典内容,其核心思想通过元素间的比较操作确定相对顺序。本文将深入探讨冒泡排序的优化策略、选择排序的变种实现、插入排序的典型应用场景,并通过统计比较次数直观展示算法效率差异。 一、冒泡排序的优化策略 传统冒泡排序存…...
项目流程中关键节点的测试类型
一、全流程测试框架图 #mermaid-svg-LmUdhLObstSpThwP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-LmUdhLObstSpThwP .error-icon{fill:#552222;}#mermaid-svg-LmUdhLObstSpThwP .error-text{fill:#552222;strok…...
EasyRTC嵌入式音视频通信SDK:WebRTC技术下的硬件与软件协同演进,开启通信新时代
在当今数字化时代,智能设备的普及和人们对实时通信需求的不断增长,推动了嵌入式音视频通信技术的快速发。EasyRTC嵌入式音视频通信SDK凭借其独特的技术特点和应用优势,在嵌入式设备和多平台实时通信领域脱颖而出。 1、轻量级设计与高性能 Ea…...
机器视觉工程师如何看机器视觉展会,有些机器视觉兄弟参加机器视觉展会,真的是参加了?重在参与?
作为机器视觉工程师,参加机器视觉展会不仅是了解行业前沿技术的窗口,也是拓展专业网络、寻找解决方案的重要机会。以下是结合展会信息和工程师视角的综合建议: 一、聚焦技术趋势与创新应用 参与技术论坛与研讨会 展会同期的技术论坛是获取行业洞见的核心渠道。例如: 上海展…...
重温Ubuntu 24.04 LTS
用户调整 # 创建新用户 sudo adduser newusername # 设置新用户的密码 sudo passwd newusername # 将新用户添加到 sudo 组 sudo usermod -aG sudo newusername # 修改ssh访问权限 sudo nano /etc/ssh/sshd_config # 将新用户加入,此时root将无法访问 AllowUsers n…...
新版 eslintrc 文件弃用 .eslintignore已弃用 替代方案
1.进入eslint.config.mjs文件 2.import { defineConfig, globalIgnores } from "eslint/config"; 引入globalIgnores 3.配置 defineConfig([ ... globalIgnores([ "config/*", ".husky", ".local", "public/*", ".…...
优化 SQL 语句方向和提升性能技巧
优化 SQL 语句是提升 MySQL 性能的关键步骤之一。通过优化 SQL 语句,可以减少查询时间、降低服务器负载、提高系统吞吐量。以下是优化 SQL 语句的方法、策略和技巧: 一、优化 SQL 语句的方法 1. 使用 EXPLAIN 分析查询 作用:查看 SQL 语句的执行计划,了解查询是如何执行的…...
数据可视化革命!「图表狐」五大行业新范式:从科研论文到商业决策的AI进化论
图表狐 - AI图表生成工具,在线数据可视化 一、学术研究:突破传统制图范式 案例1 基因测序热图 用户输入: "绘制差异表达基因热图,行标签为GeneA/B/C,列包含正常组5例、癌症组7例,红色标记上调基因(f…...
Jenkins集成Trivy安全漏洞检查指南
要将Jenkins与Trivy集成以实现制品的安全漏洞检查,可以按照以下步骤操作: 安装Trivy 在Jenkins服务器或构建节点上安装Trivy # 使用包管理器(如Debian/Ubuntu) sudo apt-get install -y wget apt-transport-https gnupg lsb-rel…...
git使用钩子文件出现错误
git的钩子文件出现错误 问题打印:解决办法1.删除本地钩子文件2. 恢复commit-msg钩子3.重新提交工程 问题打印: 无法commit 1 个文件: .git/hooks/commit-msg: 行 1: 未预期的符号 < 附近有语法错误 .git/hooks/commit-msg: 行 1: Your browse does …...
SpringBoot 第二课(Ⅱ)配置嵌入式服务器
目录 一、封装类解读 二、注册Servlet三大组件(Servlet、Filter、Listener) 自定义这三个组件 WebConfig MyFilter MyListener HelloController hello1.html hello2.html 三、使用外置的Servlet容器 1.一定要确保打包方式是war包 2.将…...
Python学习笔记(6)
Python学习笔记(6) 第13节课 函数基础1.函数定义与调用2.函数的返回值3.局部变量与全局变量 第13节课 函数基础 对于任何一个知识点,必须讨论的三个问题: (1)它是啥 (2)为啥有它 …...
HarmonyOS Next应用架构设计与模块化开发详解
引言 在HarmonyOS Next开发中,合理的应用架构设计和模块化开发是构建高效、可维护应用的关键。本文将深入探讨HarmonyOS Next应用的架构设计思路,并通过实际代码示例展示如何实现模块化开发。 应用架构设计 HarmonyOS Next应用通常采用分层架构设计&…...
batman-adv 优化:基于信号强度(RSSI)选择链路
batman-adv 优化:基于信号强度(RSSI)选择链路 1. 背景介绍 batman-adv(Better Approach To Mobile Ad-hoc Networking Advanced) 是一种用于无线 Mesh 网络的路由协议。它主要基于 ETX(Expected Transmis…...
计算机二级:函数基础题
函数基础题 第一题 rinput("请输入半径:") c3.1415926*r*2 print("{:.0f}".format(c))输出: Type Error第二题 a7 b2 print(a%2)输出 1第三题 ab4 def my_ab(ab,xy):abpow(ab,xy)print(ab,end"\n") my_ab(ab,2)prin…...
系统思考与心智模式
“问题不是出在我们做了多少,而是出在我们做了什么。” — 赫尔曼凯恩 “一分耕耘一分收获”,这似乎是我们脑海中根深蒂固的心智模式。今天,我在一家餐厅用餐,店员告诉我,打卡收藏可以获得一份小食。没过多久…...
高考志愿填报管理系统基于Spring Boot SSM
目录 摘要 一、系统需求分析: 1.1用户主体分析 1.2 功能需求分析 1.3、非功能需求分析 二、技术实现: 三、结论: 摘要 该系统主要实现了:学生信息管理、院校信息查询、专业信息展示、志愿填报模拟、智能推荐管…...
[深度学习]图像分类项目-食物分类
图像分类项目-食物分类(监督学习和半监督学习) 文章目录 图像分类项目-食物分类(监督学习和半监督学习)项目介绍数据处理设定随机种子读取文件内容图像增广定义Dataset类 模型定义迁移学习 定义超参Adam和AdamW 训练过程半监督学习定义Dataset类模型定义定义超参训练过程 项目介…...
Qt在ARM中,如何使用drmModeObjectSetProperty 设置 Plane 的 zpos 值
在 Qt 中直接使用 drmModeObjectSetProperty 设置 Plane 的 zpos 值需要结合 Linux DRM/KMS API 和 Qt 的底层窗口系统(如 eglfs 平台插件)。以下是详细步骤和代码示例: 1. 原理说明 DRM/KMS 基础: Plane:负责图层合成…...
springboot milvus search向量相似度查询 踩坑使用经验
1.前提提要:java的pom 版本为:2.4.9 milvus 版本是:2.4.13-hotfix 2.先来工具类方法 /*** 向量搜索* param client* param query* return*/public SearchResp search(NonNull MilvusClientV2 client, NonNull VectorCondition query) {final …...
BFS解决FloodFill算法
1.图像渲染 733. 图像渲染 - 力扣(LeetCode) 1.题目解析 有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sc 和 color 。你应该从像素 image[sr][sc] 开始对图像进行…...
计算机组成原理
计算机组成原理是计算机科学与技术领域的一门基础课程,它主要研究计算机硬件系统的结构、设计和工作原理。通过学习计算机组成原理,可以深入理解计算机是如何执行程序的,从最底层的角度了解计算机的工作机制。以下是计算机组成原理的一些核心…...
Spring Boot整合SSE实现消息推送:跨域问题解决与前后端联调实战
摘要 本文记录了一次完整的Spring Boot整合Server-Sent Events(SSE)实现实时消息推送的开发过程,重点分析前后端联调时遇到的跨域问题及解决方案。通过CrossOrigin注解的实际应用案例,帮助开发者快速定位和解决类似问题。 一、项…...
硅基流动:推理加速,告别“服务器繁忙,请稍后再试”
DeepSeek虽然一直热度高涨,但存在一个很直接的问题——“服务器繁忙,请稍后再试”。 一、介绍概况 硅基流动(SiliconFlow)是北京硅基流动科技有限公司推出的AI基础设施(AI Infra)平台,成立于202…...