RabbitMQ 高级特性

目录

1.消息确认

1.1 消息确认机制

1.2 手动确认方法

1. 2.1肯定确认

1.2.2 否定确认

1.3 SpringBoot 代码示例

1.3.1 配置确认机制

1.3.2 配置队列,交换机,绑定关系

1.3.3 生产者(向 rabbitmq 发送消息)

1.3.4 消费者(消费队列中的信息)

2.持久性

2.1 交换机持久化

2.2 队列持久化

2.3 消息持久化

Java 原生API 发送非持久化和持久化消息

Spring 的 RabbitTemplate 发送持久化消息

2.4 将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?

3. 发送方确认

3.1 confirm 确认模式

3.1.1 配置 RabbitMQ

3.1.2. 设置确认回调逻辑并发送消息

RabbitTemplate.ConfirmCallback (Spring)和 ConfirmListener (JDK)区别

3.2 return 退回模式

3.2.1. 配置 RabbitMQ

3.2.2. 设置返回回调逻辑并发送消息

rabbitTemplate.setMandatory(true);

ReturnedMessage

3.3 常见面试题

4. 重试机制

4.1 重试配置

4.2 配置交换机&队列

4.3 发送消息

4.4 消费消息

4.5 测试

4.6 手动确认

4.7 注意

5. TTL

5.1 设置消息的 TTL

5.1.1 先看针对每条消息设置 TTL

配置交换机&队列

发送消息

运⾏程序,观察结果

5.2 设置队列的 TTL

配置队列和绑定关系

发送消息

运⾏程序,观察结果

5.3 两者区别

6. 死信队列

6.1 死信的概念

6.2 代码示例

6.2.1 声明队列和交换机

6.2.2 正常队列绑定死信交换机

6.2.3 制造死信产生的条件

6.2.4 发送消息

6.2.5 测试死信

1. 程序启动之后,观察队列

2. 测试过期时间,到达过期时间之后,进⼊死信队列

3. 测试达到队列⻓度,消息进⼊死信队列

4. 测试消息拒收

6.3 常见面试题

1. 死信队列的概念

2. 死信的来源

3. 死信队列的应用场景

7. 延迟队列

7.1 概念

7.2 应用场景

7.3 TTL+死信队列实现

7.3.1 声明队列

7.3.2 生产者

7.2.3 消费者

7.2.4 测试

7.2.4 存在问题

7.4 延迟队列插件

7.4.1 下载并上传插件

7.4.2. 启动插件

7.4.3. 验证插件

7.5 基于插件延迟队列实现

7.5.1. 声明交换机,队列,绑定关系

7.5.2. 生产者

7.5.3. 消费者

7.5.4. 运行程序,并测试

7.6 常见面试题

7.6.1 介绍下 RabbitMQ 的延迟队列

8. 事务

8.1 配置事务管理器和开启事务

8.2 声明队列

8.3 生产者

8.4 测试

9. 消息分发

9.1 概念

9.2 应用场景

9.2.1 限流

1. 配置 prefetch 参数,设置应答⽅式为⼿动应答

2. 配置交换机,队列

3. 发送消息,⼀次发送 20 条消息

4. 消费者监听

5. 测试

9.2.2 负载均衡

1. 配置prefetch参数,设置应答⽅式为⼿动应答

2. 启动两个消费者

3. 测试


1.消息确认

1.1 消息确认机制

⽣产者发送消息之后,到达消费端之后,可能会有以下情况:

a. 消息处理成功

b. 消息处理异常

        RabbitMQ 向消费者发送消息之后,就会把这条消息删掉,那么第两种情况,就会造成消息丢失.

         那么如何确保消费端已经成功接收了,并正确处理了呢?

        为了保证消息从队列可靠地到达消费者,RabbitMQ 提供了消息确认机制(message acknowledgement)。消费者在订阅队列时,可以指定 autoAck 参数,根据这个参数设置,消息确认机制分为以下两种:

         • ⾃动确认: 当autoAck 等于true时,RabbitMQ 会⾃动把发送出去的消息置为确认,然后从内存(或 者磁盘)中删除,⽽不管消费者是否真正地消费到了这些消息.⾃动确认模式适合对于消息可靠性要求不⾼的场景.

        • ⼿动确认:当 autoAck 等于 false 时,RabbitMQ 会等待消费者显式地调⽤ Basic.Ack 命令,回复确认信号后才从内存(或者磁盘)中移去消息.这种模式适合对消息可靠性要求⽐较⾼的场景.

        消费信息的方法:

String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;

代码示例:

DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, 
AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到消息: " + new String(body));}
};
channel.basicConsume(Constants.TOPIC_QUEUE_NAME1, true, consumer);

        当 autoAck 参数置为 false,对于 RabbitMQ 服务端⽽⾔,队列中的消息分成了两个部分:

⼀. 是等待投递给消费者的消息.

⼆. 是已经投递给消费者,但是还没有收到消费者确认信号的消息. 如果 RabbitMQ ⼀直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则 RabbitMQ 会安排该消息重新进⼊队列,等待投递给下⼀个消费者,当然也有可能还是原来的那个消费者.

        

        从 RabbitMQ 的 Web 管理平台上,也可以看到当前队列中 Ready(要发送给消费者的信息) 状态和 Unacked (发送给消费者还没有得到确认的信息)状态的消息数

Ready:等待投递给消费者的消息数

Unacked:已经投递给消费者,但是未收到消费者确认信号的消息数

1.2 手动确认方法

        消费者在收到消息之后,可以选择确认,也可以选择直接拒绝或者跳过,RabbitMQ 也提供了不同的确认应答的⽅式,消费者客户端可以调⽤与其对应的 channel 的相关⽅法,共有以下三种

1. 2.1肯定确认

Channel.basicAck(long deliveryTag, boolean multiple) 

        RabbitMQ 已知道该消息并且成功的处理消息.可以将其丢弃了.

        参数说明:

        1) deliveryTag: 消息的唯⼀标识,它是⼀个单调递增的 64 位的⻓整型值.deliveryTag 是每个通道 (Channel)独⽴维护的,所以在每个通道上都是唯⼀的.当消费者确认(ack)⼀条消息时,必须使⽤对应的通道上进⾏确认.

        2)multiple:是否批量确认.在某些情况下,为了减少⽹络流量,可以对⼀系列连续的 deliveryTag 进 ⾏批量确认.值为 true 则会⼀次性 ack 所有⼩于或等于指定 deliveryTag 的消息.值为false,则只确认当前指定 deliveryTag 的消息.

        deliveryTag 是 RabbitMQ 中消息确认机制的⼀个重要组成部分,它确保了消息传递的可靠性和顺序性。

1.2.2 否定确认

        Channel.basicReject(long deliveryTag, boolean requeue)  RabbitMQ 在 2.0.0 版本开始引⼊了 Basic.Reject 这个命令,消费者客户端可以调⽤ channel.basicReject ⽅法来告诉 RabbitMQ 拒绝这个消息. 参数说明:

        1) deliveryTag: 参考channel.basicAck

        2) requeue:表⽰拒绝后,这条消息如何处理. 如果 requeue 参数设置为 true,则 RabbitMQ 会重新将这条消息存⼊队列,以便可以发送给下⼀个订阅的消费者.如果 requeue 参数设置为 false,则RabbitMQ 会把消息从队列中移除,⽽不会把它发送给新的消费者.

        3. 否定确认: Channel.basicNack(long deliveryTag, boolean multiple, boolean requeue) Basic.Reject 命令⼀次只能拒绝⼀条消息,如果想要批量拒绝消息,则可以使⽤ Basic.Nack 这个命令.消费者客户端可以调⽤ channel.basicNack ⽅法来实现.

        参数介绍参考上⾯两个⽅法.multiple 参数设置为 true 则表⽰拒绝 deliveryTag 编号之前所有未被当前消费者确认的消息

1.3 SpringBoot 代码示例

        基于 SpringBoot 来演⽰消息的确认机制,使⽤⽅式和使⽤ RabbitMQ Java Client 库有⼀定差异.

Spring-AMQP 对消息确认机制提供了三种策略.

public enum AcknowledgeMode { NONE,MANUAL,AUTO;
}

1. AcknowledgeMode.NONE 

        ◦ 这种模式下,消息⼀旦投递给消费者,不管消费者是否成功处理了消息,RabbitMQ 就会⾃动确认 消息,从 RabbitMQ 队列中移除消息.如果消费者处理消息失败,消息可能会丢失.

2. AcknowledgeMode.AUTO(默认)

        ◦ 这种模式下,消费者在消息处理成功时会⾃动确认消息,但如果处理过程中抛出了异常,则不会确认消息.

3. AcknowledgeMode.MANUAL

        ◦ ⼿动确认模式下,消费者必须在成功处理消息后显式调⽤ basicAck ⽅法来确认消息.如果消 息未被确认, RabbitMQ 会认为消息尚未被成功处理,并且会在消费者可⽤时重新投递该消息,这 种模式提⾼了消息处理的可靠性,因为即使消费者处理消息后失败,消息也不会丢失,⽽是可以被重新处理.

1.3.1 配置确认机制

spring:rabbitmq:host: 192.168.66.129port: 5672virtual-host: wuyulinusername: wuyulinpassword: wuyulinlistener:simple:#acknowledge-mode: none#acknowledge-mode: autoacknowledge-mode: manual

1.3.2 配置队列,交换机,绑定关系

package com.yulin.rabbitmqadvancedfeatures.configuration;import com.yulin.rabbitmqadvancedfeatures.constants.RabbitMQConstant;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2025-01-01* Time: 23:32*/
@Configuration
public class RabbitMQConfiguration {/*** 声明 ackExchange 交换机* */@Bean("ackExchange")public Exchange ackExchange(){return ExchangeBuilder.topicExchange(RabbitMQConstant.ACK_EXCHANGE_NAME).durable(true).build();}//2. 队列@Bean("ackQueue")public Queue ackQueue() {return QueueBuilder.durable(RabbitMQConstant.ACK_QUEUE).build();}//3. 队列和交换机绑定 Binding@Bean("ackBinding")public Binding ackBinding(@Qualifier("ackExchange") Exchange exchange,@Qualifier("ackQueue") Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("ack").noargs();}
}

1.3.3 生产者(向 rabbitmq 发送消息)

package com.yulin.rabbitmqadvancedfeatures.controller;import com.yulin.rabbitmqadvancedfeatures.constants.RabbitMQConstant;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2025-01-01* Time: 23:38*/
@RestController
@RequestMapping("/producer")
public class ProductController {@Autowiredprivate RabbitTemplate rabbitTemplate;@RequestMapping("/ack")public String ack(){rabbitTemplate.convertAndSend(RabbitMQConstant.ACK_EXCHANGE_NAME, "ack", "consumer ack test...");return "发送成功!";}}

1.3.4 消费者(消费队列中的信息)

package com.yulin.rabbitmqadvancedfeatures.listener;import com.rabbitmq.client.Channel;
import com.yulin.rabbitmqadvancedfeatures.constants.RabbitMQConstant;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2025-01-01* Time: 23:40*/
@Component
public class AckQueueListener {//指定监听队列的名称@RabbitListener(queues = RabbitMQConstant.ACK_QUEUE)public void ListenerQueue(Message message, Channel channel) throws Exception {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {System.out.printf("接收到消息: %s, deliveryTag: %d/n",new String(message.getBody(),"UTF-8"), deliveryTag);//模拟处理失败int num = 3/0;//⼿动签收//deliveryTag:这是一个长整型(long)参数,代表了需要确认的消息的唯一标识符。当消息从队列中被获取(通常是通过 basicConsume 方法)时,每条消息都会被分配一个 deliveryTag。//true:这个布尔值参数表示消息是否只应被当前消费者确认。如果是 true,则消息只会被当前消费者确认,不会被其他消费者再次确认。如果是 false,则消息可能会被其他消费者确认,这在多消费者环境中有时是有用的。channel.basicAck(deliveryTag, true);System.out.println("处理完成");}catch (Exception e){//异常了就拒绝签收//第三个参数requeue, 是否重新发送, 如果为true, 则会重新发送,,若为false, 则直接丢弃channel.basicNack(deliveryTag, true,true);System.out.println("处理异常");}}
}

2.持久性

        我们如何保证当 RabbitMQ 服务停掉以后,⽣产者发送的消息不丢失呢.默认情况下,RabbitMQ 退出或者由于某种原因崩溃时,会忽视队列和消息,除⾮告知他不要这么做.RabbitMQ 的持久化分为三个部分:

交换器的持久化

队列的持久化

消息的持久化.

2.1 交换机持久化

        交换器的持久化是通过在声明交换机时是将 durable 参数置为 true 实现的.相当于将交换机的属性在服务器内部保存,当 MQ 的服务器发⽣意外或关闭之后,重启 RabbitMQ 时不需要重新去建⽴交换机,交换机会⾃动建⽴,相当于⼀直存在.如果交换器不设置持久化,那么在 RabbitMQ 服务重启之后,相关的交换机元数据会丢失,对⼀个⻓期使⽤的交换器来说,建议将其置为持久化的.

ExchangeBuilder.topicExchange(Constant.ACK_EXCHANGE_NAME).durable(true).build()

2.2 队列持久化

        队列的持久化是通过在声明队列时将 durable 参数置为 true实现的. 如果队列不设置持久化,那么在 RabbitMQ 服务重启之后,该队列就会被删掉,此时数据也会丢失.(队列没有了,消息也⽆处可存了) 队列的持久化能保证该队列本⾝的元数据不会因异常情况⽽丢失,但是并不能保证内部所存储的消息不会丢失.要确保消息不会丢失,需要将消息设置为持久化.我前⾯博客⽤的创建队列的⽅式都是持久化

QueueBuilder.durable(Constant.ACK_QUEUE).build();

        点进去看源码会发现,该⽅法默认 durable 是 true

public static QueueBuilder durable(String name) {return (new QueueBuilder(name)).setDurable();
}
private QueueBuilder setDurable() {this.durable = true;return this;
}

通过下⾯代码,可以创建非持久化的队列

QueueBuilder.nonDurable(Constant.ACK_QUEUE).build(); 

2.3 消息持久化

        消息实现持久化,需要把消息的投递模式( MessageProperties 中的 deliveryMode )设置为2, 也就是 MessageDeliveryMode.PERSISTENT

public enum MessageDeliveryMode {NON_PERSISTENT,//⾮持久化 PERSISTENT;//持久化 
}

        设置了队列和消息的持久化,当 RabbitMQ 服务重启之后,消息依旧存在.

        如果只设置队列持久化,重启之后消息会丢失.

        如果只设置消息的持久化,重启之后队列消失,继⽽消息也丢失.所以单单设置消息 持久化⽽不设置队列的持久化显得毫⽆意义.

Java 原生API 发送非持久化和持久化消息

//⾮持久化信息 
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
//持久化信息 
channel.basicPublish("",QUEUE_NAME, 
MessageProperties.PERSISTENT_TEXT_PLAIN,msg.getBytes());

Spring 的 RabbitTemplate 发送持久化消息

// 要发送的消息内容 
String message = "This is a persistent message";// 创建⼀个Message对象,设置为持久化 
Message messageObject = new Message(message.getBytes(), new 
MessageProperties());
messageObject.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
// 使⽤RabbitTemplate发送消息 
rabbitTemplate.convertAndSend(Constant.ACK_EXCHANGE_NAME, "ack", 
messageObject);

        RabbitMQ 默认情况下会将消息视为持久化的,除非队列被声明为非持久化,或者消息在发送时被标记为非持久化

        注意将所有的消息都设置为持久化,会严重影响 RabbitMQ 的性能(随机).、写⼊磁盘的速度⽐写⼊内存的速度慢得不只⼀点点.对于可靠性不是那么⾼的消息可以不采⽤持久化处理以提⾼整体的吞吐量.在选择是否要将消息持久化时,需要在可靠性和吐吞量之间做⼀个权衡.

2.4 将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?

        将交换器、队列、消息都设置了持久化之后就能百分之百保证数据不丢失了吗?

        答案是否定的. 

        1. 从消费者来说,如果在订阅消费队列时将 autoAck 参数设置为 true,那么当消费者接收到相关消息之后,还没来得及处理就宕机了,这样也算数据丢失.这种情况很好解决,将 autoAck 参数设置为 false,并进⾏⼿动确认.

        2. 在持久化的消息正确存⼊RabbitMQ之后,还需要有⼀段时间(虽然很短,但是不可忽视)才能存⼊磁盘 中.RabbitMQ 并不会为每条消息都进⾏同步存盘(调⽤内核的 fsync ⽅法)的处理,可能仅仅保存到操作系统缓存之中⽽不是物理磁盘之中.如果在这段时间内 RabbitMQ 服务节点发⽣了宕机、重启等异常情况,消息保存还没来得及落盘,那么这些消息将会丢失.

这个问题怎么解决呢 ?

        1. 引⼊RabbitMQ 的仲裁队列(后⾯再讲),如果主节点(master)在此特殊时间内挂掉,可以⾃动切换到从节点(slave),这样有效地保证了⾼可⽤性,除⾮整个集群都挂掉(此⽅法也不能保证100%可靠,但是配置了仲裁队列要⽐没有配置仲裁队列的可靠性要⾼很多,实际⽣产环境中的关键业务队列⼀般都会设置仲裁队列).

        2. 还可以在发送端引⼊事务机制或者发送⽅确认机制来保证消息已经正确地发送并存储⾄RabbitMQ 中,详细参考下⼀个章节内容介绍--"发送⽅确认"

3. 发送方确认

        在使⽤ RabbitMQ 的时候,可以通过消息持久化来解决因为服务器的异常崩溃⽽导致的消息丢失,但是还有⼀个问题,当消息的⽣产者将消息发送出去之后,消息到底有没有正确地到达服务器呢?

        如果在消息到达服务器之前已经丢失(比如 RabbitMQ 重启,那么 RabbitMQ 重启期间⽣产者消息投递失败),持久化操作也解决不了这个问题,因为消息根本没有到达服务器,何谈持久化? RabbitMQ 为我们提供了两种解决⽅案:

        a. 通过事务机制实现

        b. 通过发送⽅确认(publisher confirm)机制实现

        事务机制⽐较消耗性能,在实际⼯作中使⽤也不多,咱们主要介绍 confirm 机制来实现发送⽅的确认.RabbitMQ 为我们提供了两个⽅式来控制消息的可靠性投递

1. confirm 确认模式

2. return 退回模式

3.1 confirm 确认模式

        Producer 在发送消息的时候,对发送端设置⼀个 ConfirmCallback 的监听,⽆论消息是否到达 Exchange,这个监听都会被执⾏,如果 Exchange 成功收到,ACK( Acknowledge character ,确认 字符)为 true,如果没收到消息,ACK 就为 false.

步骤如下:

1. 配置RabbitMQ

2. 设置确认回调逻辑并发送消息

接下来看实现步骤

3.1.1 配置 RabbitMQ

# 应用服务 WEB 访问端口
server:port: 8081
spring:rabbitmq:host: 192.168.66.129port: 5672virtual-host: wuyulinusername: wuyulinpassword: wuyulin#配置消息确认机制listener:simple:# 这种模式下,消息⼀旦投递给消费者,不管消费者是否成功处理了消息,RabbitMQ 就会⾃动确认 消息,从 RabbitMQ 队列中移除消息.如果消费者处理消息失败,消息可能会丢失.#acknowledge-mode: none# (默认)这种模式下,消费者在消息处理成功时会自动确认消息,但如果处理过程中抛出了异常,则不会确认消息.#acknowledge-mode: auto# ⼿动确认模式下,消费者必须在成功处理消息后显式调用 basicAck ⽅法来确认消息.如果消息未被确认, RabbitMQ 会认为消息尚未被成功处理,并且会在消费者可用时重新投递该消息,这种模式提⾼了消息处理的可靠性,因为即使消费者处理消息后失败,消息也不会丢失,而是可以被重新处理.acknowledge-mode: manual# 配置发送方确认机制publisher-confirm-type: correlated

3.1.2. 设置确认回调逻辑并发送消息

        ⽆论消息确认成功还是失败,都会调⽤ ConfirmCallback 的 confirm ⽅法.如果消息成功发送到MQ, ack 为 true.如果消息发送失败,ack 为 false,并且 cause 提供失败的原因.

        注入一个新的 RabbitTemplate 对象,设置发送方确认,并确认回调逻辑

@Configuration
public class RabbitMQConfiguration {//如果单独注入新的 confirmRabbitTemplate 对象,会将普通的 rabbitTemplate 也改掉,所以还需要注入一个普通的 rabbitTemplate 对象//普通的 RabbitTemplate@Bean("rabbitTemplate")public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);return rabbitTemplate;}//配置了发送方确认机制的 RabbitTemplate@Bean("confirmRabbitTemplate")public RabbitTemplate confirmRabbitTemplate(ConnectionFactory connectionFactory){RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setConfirmCallback(new  RabbitTemplate.ConfirmCallback(){@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {System.out.printf("");if (ack){System.out.printf("消息接收成功, id:%s \n", correlationData.getId()

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

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

相关文章

AIGC视频生成模型:Meta的Emu Video模型

大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Meta的视频生成模型Emu Video,作为Meta发布的第二款视频生成模型,在视频生成领域发挥关键作用。 🌺优质专栏回顾&am…

面向对象的程序设计:以对象的方式进行思考

1 理解接口与实现的区别 以上一篇文章的电视机需要插电使用的例子继续来讲解: 对电视而言,插电使用,只需要标准的插座即可,具体的电从哪里来,是火力发电厂,或是太阳能发电,亦或是畜电池逆变供电,电视机是不需要关心的。 发电厂或供电设备属于实现,220V交流电插座属于…

要获取本地的公网 IP 地址(curl ifconfig.me)

文章目录 通过命令行查询(适用于 Linux/Mac/Windows)Linux/MacWindows 注意事项 要获取本地的公网 IP 地址,可以通过以下简单的方法: 通过命令行查询(适用于 Linux/Mac/Windows) Linux/Mac 打开终端。输入…

MySQL 数据库 UDF 提权

免责声明 本博客文章仅供教育和研究目的使用。本文中提到的所有信息和技术均基于公开来源和合法获取的知识。本文不鼓励或支持任何非法活动,包括但不限于未经授权访问计算机系统、网络或数据。 作者对于读者使用本文中的信息所导致的任何直接或间接后果不承担任何责…

【数据分享】1929-2024年全球站点的逐年平均气温数据(Shp\Excel\无需转发)

气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据!本次我们为大家带来的就是具体到气象监…

【Linux 源码】内核态到用户态

文章目录 1. 由来2. 流程图3. 中断3.1 概念3.2 8259A芯片3.4 中断时的栈处理3.4.1 相同特权级3.4.2 不同特权级 3.5 中断流程3.6 定位中断程序3.7 中断流程步骤总结 4. 源码4.1 move_to_user_mode4.2 0号进程4.3 TSS和LDT在GDT表排布4.4 ldt中的0x17栈段 5. 总结 1. 由来 ​ 首…

雷电9最新版安装Magisk+LSPosd(新手速通)

大家好啊!我是NiJiMingCheng 我的博客:NiJiMingCheng 在安卓系统的定制与拓展过程中,获取 ROOT 权限以及安装各类框架是进阶玩家常用的操作,这可以帮助我们实现更多系统层面的个性化功能。今天,我将为大家详细介绍如何…

《Linux服务与安全管理》| 邮件服务器安装和配置

《Linux服务与安全管理》| 邮件服务器安装和配置 目录 《Linux服务与安全管理》| 邮件服务器安装和配置 1.在Server01上安装dns、postfix、dovecot和telnet,并启动 2.在Server01上配置DNS服务器,设置MX资源记录 3.在server1上…

计算机毕业设计Python电商品推荐系统 商品比价系统 电商比价系统 商品可视化 商品爬虫 机器学习 深度学习 京东爬虫 国美爬虫 淘宝爬虫 大数据

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

【银河麒麟高级服务器操作系统】业务访问慢网卡丢包现象分析及处理过程

了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:product.kylinos.cn 开发者专区:developer.kylinos.cn 文档中心:document.kylinos.cn 交流论坛:forum.kylinos.cn 服务器环境以及配置 【内核版本…

鸿蒙开发中的骨架图:提升用户体验的关键一环

大家好,我是小 z,今天要给大家分享一个提升用户体验的超实用技巧 —— 骨架图🎯 文章目录 一、什么是骨架图二、骨架图的作用三、鸿蒙开发中实现骨架图的方法1. 利用 opacity 奠定视觉基础2. animateTo 驱动动态变化3. 二者协同触发与展示 四…

leetcode刷题记录(七十三)——543. 二叉树的直径

(一)问题描述 543. 二叉树的直径 - 力扣(LeetCode)543. 二叉树的直径 - 给你一棵二叉树的根节点,返回该树的 直径 。二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 r…

【esp32小程序】小程序篇02——连接git

一、创建仓库 进入gitee官网,登录(如果没有gitee账号的就自行注册一下)。 点击号-->新建仓库 填写好必填信息,然后点击“创建” 二、微信开发者工具配置 在微信开发者工具打开我们的项目。按下面的步骤依次点击 三、验证 点…

Linux的基本指令(上) -- 0基础入门

目录 知识点引入 基本指令 ls指令 pwd 命令 cd 指令 touch 指令 stat指令 mkdir 指令 tree指令 rmdir 指令 rm 命令 man 指令 which 指令 alias 指令 echo指令 输出重定向: > 追加重定向:>> cp 指令 知识点引入 1. Linux中路径用 / 作为路径分隔…

Java测试开发平台搭建(九)前端

1. 搭建前端vue环境 Vue3 安装 | 菜鸟教程 2. 创建项目 1.进入ui vue ui 2. create项目 3. 成功之后添加插件: cli-plugin-router vue-cli-plugin-vuetify 4. 添加依赖 axios 5. 点击任务开始运行 如果报错: 修改vue.config.jsconst { defineConfig }…

基于SpringBoot+Vue的智慧动物园管理系统的设计与实现

获取源码:基于SpringBootVue智慧动物园系统设计与实现: 后台和用户前台。后台包括首页、员工管理、考勤管理、部门管理、角色管理、审核管理、动物管理、演出管理、园区管理、园区设施维修、饲养管理、行为观察管理、疫苗管理、看护管理、个人中心、票务管理、收入管…

55.【5】BUUCTF WEB NCTF2019 sqli

进入靶场 输入admin 123 过滤的这么严格??? 过滤很严格,此时要么爆破,要么扫描 直接扫描,得到robots.txt 访问后又得到hint.txt 继续访问 图片内容如下 $black_list "/limit|by|substr|mid|,|admi…

【前端】用OSS增强Hexo的搜索功能

文章目录 前言配置 _config.fluid.yml云端实时更新 local-search.xml解决 OSS.Bucket 的跨域问题 前言 原文地址:https://blog.dwj601.cn/FrontEnd/Hexo/hexo-enhance-local-search-with-oss/ 考虑到某著名云服务商提供的云服务器在两年的 99 计划后续费价格高达四…

Hive SQL必刷练习题:留存率问题

首次登录算作当天新增,第二天也登录了算作一日留存。可以理解为,在10月1号登陆了。在10月2号也登陆了,那这个人就可以算是在1号留存 今日留存率 (今日登录且明天也登录的用户数) / 今日登录的总用户数 * 100% 解决思…

Ubuntu 24.04 LTS 系统语言英文改中文

Ubuntu 24.04 LTS 修改软件源 Ubuntu 更改软件源 修改语言 无需输入命令,为Ubuntu 24.04系统添加中文智能拼音输入法 在 setting 的 system 中按下图操作 点击“Apply Changes”。需要管理员密码,安装完成后,退出登录,重新登…