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

RabbitMQ 中的六大工作模式介绍与使用

文章目录

    • 简单队列(Simple Queue)模式
      • 配置类定义
      • 消费者定义
      • 发送消息测试消费
    • 工作队列(Work Queues)模式
      • 配置类定义
      • 消费者定义
      • 发送消息测试消费
      • 负载均衡调优
    • 发布/订阅(Publish/Subscribe)模式
      • 配置类定义
      • 消费者定义
      • 发送消息测试消费
    • 路由(Routing)模式
      • 配置类定义
      • 消费者定义
      • 发送消费测试消费
    • 主题(Topics)模式
      • 配置类定义
      • 消费者定义
      • 发送消息测试消费
    • RPC(Remote Procedure Call)模式
      • 配置类定义
      • 请求与响应实体类
      • 消费者定义
      • 发送消息测试消费

简单队列(Simple Queue)模式

  • 结构:一个生产者对应一个消费者,生产者将消息发送到指定队列,消费者从该队列获取消息。
  • 工作流程:生产者创建一个消息并发送到 RabbitMQ 的队列中,消费者从这个队列里取出消息进行处理。
  • 应用场景:适用于任务处理逻辑简单,对消息处理速度要求不高,且消息处理顺序要求不严格的场景,比如简单的日志收集系统。

以下是简单队列(Simple Queue)模式的使用案例。

配置类定义

package test;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SimpleQueueConfig {@Beanpublic DirectExchange simpleQueueExchange() {return ExchangeBuilder// 指定名称为simple-queue-exchange的交换机.directExchange("simple-queue-exchange")// 声明为持久化交换机.durable(true).build();}@Beanpublic Queue simpleQueue() {return QueueBuilder// 指定一个名称为simple-queue的持久化队列.durable("simple-queue").build();}@Beanpublic Binding simpleQueueToSimpleQueueExchangebinding() {// 绑定队列给交换机,根据队列名为路由键return BindingBuilder.bind(simpleQueue()).to(simpleQueueExchange()).withQueueName();}}

消费者定义

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
@Slf4j
public class SimpleQueueConsumer {@RabbitListener(queues = "simple-queue")public void consumer(String message) {log.info("消费者接收消息:{}", message);}}

发送消息测试消费

package test;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);rabbitTemplate.convertAndSend("simple-queue", "hello world!");}}

控制台输出:

在这里插入图片描述

工作队列(Work Queues)模式

  • 结构:一个生产者对应多个消费者,多个消费者共同从一个队列中获取消息进行处理。
  • 工作流程:生产者将消息发送到队列,多个消费者从该队列中获取消息(默认采用轮询的负载均衡策略),一条消息只会被一个消费者处理。
  • 应用场景:适用于需要将大量任务分发给多个工作者并行处理的场景,例如订单处理、图片处理等。

以下是工作队列(Work Queues)模式的使用案例。

配置类定义

定义一个 DirectExchange 类型的交换机与两个队列,通过队列名作为 RoutingKey 进行绑定。

package test;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class WorkQueueConfig {@Beanpublic DirectExchange workQueueExchange(){return ExchangeBuilder.directExchange("work-queue-exchange").durable(true).build();}@Beanpublic Queue workQueue(){return QueueBuilder.durable("work-queue").build();}@Beanpublic Binding workQueueToWorkQueueExchangeBinding(){return BindingBuilder.bind(workQueue()).to(workQueueExchange()).withQueueName();}}

消费者定义

定义两个消费者,分别监听两个不同的队列。

消费者 1:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class WorkQueueConsumer01 {@RabbitListener(queues = "work-queue")public void receive(String message){log.info("WorkQueueConsumer01 receive a message:{}",message);}}

消费者 2:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class WorkQueueConsumer02 {@RabbitListener(queues = "work-queue")public void receive(String message){log.info("WorkQueueConsumer02 receive a message:{}",message);}}

发送消息测试消费

work-queue-exchange 交换机中发送 10 条消息。

package test;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);for (int i = 0; i < 10; i++) {rabbitTemplate.convertAndSend("work-queue-exchange", "work-queue", "hello world!" + i);}}}

控制台输出:

在这里插入图片描述

在上例结果,消费者 1 与消费者 2 对消息进行了轮询处理。

负载均衡调优

在工作队列模式下,多个消费者处理消息默认按照轮询的规则进行处理。但是如果其中某个消费者的处理能力比其他消费者更为强大,那么它实际上可以处理更多的消息,如果此时还是按照轮询规则来处理消息,这样是对该消费者能力的一种浪费。

对于上述情况,在 RabbitMQ 中支持调整消费者处理消息时的负载均衡策略,具体而言,即通过设置预取数量(prefetch count)参数,以实现更灵活的消息分发策略,即让处理能力更强大的消费者处理更多的消息。

在 Spring Boot 中,可以通过设置 spring.rabbitmq.listener.simple.prefetch 参数来控制消费者的预取数量:

spring:rabbitmq:listener:simple:prefetch: 1

将预取数量设置为 1,则每个消费者在处理完当前消息并确认(ACK)之后才会接收下一条消息,从而避免了某个消费者负载过重的情况。

模拟当某个消费者处理能力较弱:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class WorkQueueConsumer01 {@RabbitListener(queues = "work-queue")public void receive(String message) throws InterruptedException {// 模拟WorkQueueConsumer01处理能力较弱Thread.sleep(1);log.info("WorkQueueConsumer01 receive a message:{}",message);}}

再次向交换机发送 10 条消息,控制台输出:

在这里插入图片描述

在上述结果中,由于 WorkQueueConsumer01 处理消息的能力更弱,所以更多的消息被分摊到了 WorkQueueConsumer02 处理。

发布/订阅(Publish/Subscribe)模式

  • 结构:包含一个生产者、一个交换机(Exchange)和多个队列,多个消费者分别监听不同的队列。
  • 工作流程:生产者将消息发送到交换机,交换机将消息广播到绑定到它的所有队列,每个绑定的队列对应的消费者都能收到消息。
  • 应用场景:适用于一个消息需要被多个不同的服务或模块接收和处理的场景,如系统的通知功能。

以下是发布/订阅(Publish/Subscribe)模式的使用案例。

配置类定义

定义一个 FanoutExchange 类型的交换机与三个队列,让三个队列绑定到该交换机。

FanoutExchange 交换机不需要指定 RoutingKey。因为 FanoutExchange 交换机会将消息统一发送给与其绑定的所有队列,指定 RoutingKey 实际上没有任何意义。

package test;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class PublishSubscribeConfig {@Beanpublic Queue publishSubscribeQueue1() {return new Queue("publish-subscribe-queue-1");}@Beanpublic Queue publishSubscribeQueue2() {return new Queue("publish-subscribe-queue-2");}@Beanpublic Queue publishSubscribeQueue3() {return new Queue("publish-subscribe-queue-3");}@Beanpublic FanoutExchange publishSubscribeFanoutExchange() {return new FanoutExchange("publish-subscribe-fanout-exchange");}@Beanpublic Binding publishSubscribeBinding1() {return BindingBuilder.bind(publishSubscribeQueue1()).to(publishSubscribeFanoutExchange());}@Beanpublic Binding publishSubscribeBinding2() {return BindingBuilder.bind(publishSubscribeQueue2()).to(publishSubscribeFanoutExchange());}@Beanpublic Binding publishSubscribeBinding3() {return BindingBuilder.bind(publishSubscribeQueue3()).to(publishSubscribeFanoutExchange());}}

消费者定义

定义三个消费者,分别监听三个不同的队列。

第一个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class PublishSubscribeConsumer01 {@RabbitListener(queues = "publish-subscribe-queue-1")public void receive(String message) {log.info("PublishSubscribeConsumer 01 receive a Message:{}",message);}}

第二个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class PublishSubscribeConsumer02 {@RabbitListener(queues = "publish-subscribe-queue-2")public void receive(String message) {log.info("PublishSubscribeConsumer 02 receive a message:{}",message);}}

第三个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class PublishSubscribeConsumer03 {@RabbitListener(queues = "publish-subscribe-queue-3")public void receive(String message) {log.info("PublishSubscribeConsumer 03 receive a message:{}",message);}}

发送消息测试消费

publish-subscribe-fanout-exchange 发送一条消息。

package test;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);rabbitTemplate.convertAndSend("publish-subscribe-fanout-exchange","","hello world!");}}

控制台输出:

在这里插入图片描述

路由(Routing)模式

  • 结构:同样包含生产者、交换机和多个队列,但交换机类型为直连交换机(Direct Exchange),队列通过路由键(routing key)绑定到交换机。
  • 工作流程:生产者发送消息时指定路由键,交换机根据路由键将消息路由到与之绑定的队列,只有绑定了对应路由键的队列才能收到消息。
  • 应用场景:适用于根据不同的业务规则将消息路由到不同队列的场景,如根据日志的级别(info、error 等)将日志消息路由到不同的队列。

以下是路由(Routing)模式的使用案例。

配置类定义

定义一个 DirectExchange,因为 DirectExchange 可以通过 RoutingKey 精确匹配消息,当然也可以使用其他类型的交换机,如 ToppicExchange

定义三个不同名称的队列,其中两个队列绑定相同的 RoutingKey,而另外一个单独绑定一个队列。

package test;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RoutingConfig {@Beanpublic DirectExchange routingExchange() {return ExchangeBuilder.directExchange("routing-exchange").durable(true).build();}@Beanpublic Queue routingQueue1() {return QueueBuilder.durable("routing-queue-1").build();}@Beanpublic Queue routingQueue2() {return QueueBuilder.durable("routing-queue-2").build();}@Beanpublic Queue routingQueue3() {return QueueBuilder.durable("routing-queue-3").build();}@Beanpublic Binding routingQueue1ToRoutingExchangeBinding() {return BindingBuilder.bind(routingQueue1()).to(routingExchange()).with("routing-key-1");}@Beanpublic Binding routingQueue2ToRoutingExchangeBinding() {return BindingBuilder.bind(routingQueue2()).to(routingExchange()).with("routing-key-2");}@Beanpublic Binding routingQueue3ToRoutingExchangeBinding() {return BindingBuilder.bind(routingQueue3()).to(routingExchange()).with("routing-key-2");}}

消费者定义

定义三个消费者,分别监听三个不同的队列。

第一个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class RoutingQueueConsumer01 {@RabbitListener(queues = "routing-queue-1")public void receive(String message){log.info("RoutingQueueConsumer01 receive a message:{}",message);}}

第二个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class RoutingQueueConsumer02 {@RabbitListener(queues = "routing-queue-2")public void receive(String message){log.info("RoutingQueueConsumer02 receive a message:{}",message);}}

第三个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class RoutingQueueConsumer03 {@RabbitListener(queues = "routing-queue-3")public void receive(String message){log.info("RoutingQueueConsumer03 receive a message:{}",message);}}

发送消费测试消费

向交换机发送消息,并指定 RoutingKey 为其中的两个。

package test;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);rabbitTemplate.convertAndSend("routing-exchange", "routing-key-1", "hello world by routing-key-1!");rabbitTemplate.convertAndSend("routing-exchange", "routing-key-2", "hello world by routing-key-2!");}}

控制台输出:

在这里插入图片描述

上述结果中,三个消费者都接受到了消息并成功处理。但实际上发送消息时,交换机只向两个 RoutingKey 发送消息,而另外一个 RoutingKey 并没有发送。这样的情况下,三个消息者监听三个不同队列仍然能够接受消息并处理,这是因为它们监听的队列所绑定的 RoutingKey 都被交换机投递了消息。

主题(Topics)模式

  • 结构:包含生产者、主题交换机(Topic Exchange)和多个队列,队列通过绑定键(binding key)绑定到交换机,绑定键可以使用通配符。
  • 工作流程:生产者发送消息时指定路由键,交换机根据绑定键和路由键的匹配规则将消息路由到相应的队列。
  • 应用场景:适用于需要根据消息的主题进行灵活路由的场景,如新闻分类订阅,用户可以根据不同的主题订阅不同的新闻。

生产者发送包含主题的消息,主题由一个或多个单词组成,单词之间使用点号 . 进行分隔。消费者可以使用通配符 *# 对主题进行模糊匹配:

  • *:匹配一个单词,可以代表任意一个词。
  • #:匹配零个或多个单词,可以代表一个或多个词。

以下是主题(Topics)模式的使用案例。

配置类定义

定义一个 TopicExchange,分别通过 log.info.*log.error.#RoutingKey 绑定到两个不同的队列。

package test;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class TopicConfig {@Beanpublic Queue topicQueue1() {return new Queue("topic-queue-1");}@Beanpublic Queue topicQueue2() {return new Queue("topic-queue-2");}@Beanpublic TopicExchange topicExchange() {return new TopicExchange("topic-exchange");}@Beanpublic Binding bindingExchange() {return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("log.info.*");}@Beanpublic Binding bindingExchange2() {return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("log.error.#");}}

消费者定义

定义两个消费者分别监听两个不同队列。

第一个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class TopicQueueConsumer01 {@RabbitListener(queues = "topic-queue-1")public void receive(String message){log.info("TopicQueueConsumer01 receive a message:{}",message);}}

第二个消费者:

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Slf4j
@Service
public class TopicQueueConsumer02 {@RabbitListener(queues = "topic-queue-2")public void receive(String message){log.info("TopicQueueConsumer02 receive a message:{}",message);}}

发送消息测试消费

topic-exchange 交换机发送六条消息,通过不同的 RoutingKey

package test;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);rabbitTemplate.convertAndSend("topic-exchange", "log.info.base", "log.info.base message!");rabbitTemplate.convertAndSend("topic-exchange", "log.info.customer", "log.info.customer message!");rabbitTemplate.convertAndSend("topic-exchange", "log.info.shop.goods", "log.info.shop.goods message!");rabbitTemplate.convertAndSend("topic-exchange", "log.error.base", "log.error.base message!");rabbitTemplate.convertAndSend("topic-exchange", "log.error.customer", "log.error.customer message!");rabbitTemplate.convertAndSend("topic-exchange", "log.error.shop.goods", "log.error.shop.goods message!");}}

控制台输出:

在这里插入图片描述

RPC(Remote Procedure Call)模式

  • 结构:包含客户端(生产者)、服务端(消费者)、请求队列和响应队列。
  • 工作流程:客户端发送请求消息到请求队列,并设置一个回调队列用于接收响应;服务端从请求队列获取请求消息,处理后将响应消息发送到回调队列,客户端从回调队列获取响应。
  • 应用场景:适用于需要在分布式系统中进行远程过程调用的场景,如微服务之间的调用。

以下是主题(Topics)模式的使用案例。

配置类定义

定义一个交换机与一个队列,通过队列名进行绑定。

package test;import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RpcConfig {@Beanpublic Queue rpcQueue() {return new Queue("rpc-queue", true);}@Beanpublic DirectExchange rpcExchange() {return new DirectExchange("rpc-exchange");}@Beanpublic Binding rpcQueueToRpcExchangeBinding() {return BindingBuilder.bind(rpcQueue()).to(rpcExchange()).withQueueName();}@Beanpublic Jackson2JsonMessageConverter jackson2JsonMessageConverter() {return new Jackson2JsonMessageConverter();}}

请求与响应实体类

创建 RPC 请求与响应实体类。

package test;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@AllArgsConstructor
@NoArgsConstructor
public class RpcRequest implements Serializable {private String message;}
package test;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@AllArgsConstructor
@NoArgsConstructor
public class RpcResponse implements Serializable {private int result;}

消费者定义

定义一个消费者从队列中接收消息。

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class RpcServer {@RabbitListener(queues = "rpc-queue")public RpcResponse handleRpcRequest(RpcRequest request) {log.info("RPC接收的消息:{}", request);return new RpcResponse(0);}}

发送消息测试消费

测试 RPC 消息的发送。

package test;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;@SpringBootApplication
@Slf4j
public class SpringBootApp {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringBootApp.class, args);RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);String exchange = "rpc-exchange";String routingKey = "rpc-queue";RpcRequest rpcRequest = new RpcRequest("Rpc message!");RpcResponse rpcResponse = (RpcResponse) rabbitTemplate.convertSendAndReceive(exchange, routingKey, rpcRequest);log.info("RPC返回的结果:{}", rpcResponse);}}

控制台输出:

在这里插入图片描述

相关文章:

RabbitMQ 中的六大工作模式介绍与使用

文章目录 简单队列&#xff08;Simple Queue&#xff09;模式配置类定义消费者定义发送消息测试消费 工作队列&#xff08;Work Queues&#xff09;模式配置类定义消费者定义发送消息测试消费负载均衡调优 发布/订阅&#xff08;Publish/Subscribe&#xff09;模式配置类定义消…...

Android HttpAPI通信问题(已解决)

使用ClearTextTraffic是Android中一项重要的网络设置,它控制了应用程序是否允许在不使用HTTPS加密的情况下访问网络。在默认情况下,usescleartexttraffic的值为true,这意味着应用程序可以通过普通的HTTP协议进行网络通信。然而,这样的设置可能会引发一些安全问题,本文将对…...

【SSM-SpringMVC(二)】Spring接入Web环境!本篇开始研究SpringMVC的使用!SpringMVC数据响应和获取请求数据

SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 页面跳转&#xff1a; 返回字符串方式 直接返回字符串&#xff1a;此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转 RequestMapping("/con&…...

docker安装mysql8, 字符集,SQL大小写规范,sql_mode

一、Docker安装MySQL 使用Docker安装MySQL,命令如下 docker run -d \-p 3306:3306 \-v mysql_conf:/etc/mysql/conf.d \-v mysql_data:/var/lib/mysql \--name mysql \--restartalways \--privileged \-e MYSQL_ROOT_PASSWORD1234 \mysql:8.0.30参数解释 &#x1f433; dock…...

FastMCP v2:构建MCP服务器和客户端的Python利器

FastMCP v2&#xff1a;构建MCP服务器和客户端的Python利器 引言 在人工智能与大语言模型&#xff08;LLMs&#xff09;的应用场景中&#xff0c;如何高效地构建服务器和客户端以实现数据交互与功能调用是关键问题。Model Context Protocol (MCP) 为此提供了一种标准&#xf…...

一个WordPress连续登录失败的问题排查

文章目录 1. 问题背景2. 解决方案搜索3. 问题定位4. 排查过程5. 清理空间6. 处理结果7. 后续优化 1. 问题背景 登录请求URL: Request URL: https://www.xxxxxx.com/wp-login.php 返回的响应头信息是: location: https://www.xxxxxx.com/wp-admin/ 证明登录成功。 接下来浏览器…...

【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析

SSM整合的基础jar包 需要创建的层级&#xff1a; controller层 该层下需要创建对应的控制器Servlet POJO文件夹 该层下需要创建与数据库对应的POJO类 mapper层 该层下需要创建Mapper的接口实现 service层 该层下需要创建业务层的接口及其接口实现 需要创建的配置文件&#x…...

Go语言超时控制方案全解析:基于goroutine的优雅实现

一、引言 在构建高可靠的后端服务时&#xff0c;超时控制就像是守护系统稳定性的"安全阀"&#xff0c;它确保当某些操作无法在预期时间内完成时&#xff0c;系统能够及时止损并释放资源。想象一下&#xff0c;如果没有超时控制&#xff0c;一个简单的数据库查询卡住…...

spark运行架构及核心组件介绍

目录 1. Spark 的运行架构1.1 Driver1.2 Executor1.3 Cluster Manager1.4 工作流程 2. Spark 的核心组件2.1 Spark Core2.2 Spark SQL2.3 Spark Streaming2.4 MLlib2.5 GraphX 3. Spark 架构图4. Spark 的优势4.1 高性能4.2 易用性4.3 扩展性4.4 容错性 5. 总结 1. Spark 的运行…...

idea中编写spark程序

### 在 IntelliJ IDEA 中配置和编写 Spark 程序 要在 IntelliJ IDEA 中高效地开发 Spark 程序&#xff0c;需要完成一系列必要的环境配置以及项目搭建工作。以下是详细的说明。 --- #### 1. 安装与配置 IntelliJ IDEA 为了确保 IDE 可以支持 Scala 开发&#xff0c;首先需要…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(21):复习

日语学习-日语知识点小记-构建基础-JLPT-N4阶段&#xff08;21&#xff09;&#xff1a;复习 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰 2、知识点&#xff08;1&#xff09;じょうけん 条件形&#xff11;、復習 &#xff08;&#x…...

MYSQL数据库集群高可用和数据监控平台

项目环境 项目拓扑结构 软硬件环境清单 软硬件环境清单 软硬件环境清单 主机名IP硬件软件 master1 192.168.12.130 VIP&#xff1a;192.168.12.200 cpu:1颗2核 内 存&#xff1a;2GB HDD&#xff1a;20GB 网 络&#xff1a;NAT VmWare17 OpenEuler22.03 SP4 MySql8.0.3…...

Spark SQL 读取 CSV 文件,并将数据写入 MySQL 数据库

在 Spark 中&#xff0c;可以使用 Spark SQL 读取 CSV 文件&#xff0c;并将数据写入 MySQL 数据库。以下是一个完整的示例&#xff0c;展示如何实现这一过程。 环境准备 安装 MySQL&#xff1a;确保 MySQL 数据库已安装并运行。创建 MySQL 数据库和表&#xff1a;CREATE DAT…...

C++矩阵操作:正交矩阵(旋转矩阵)

文章目录 一、简介二、实现代码三、实现效果一、简介 我们知道判断一个矩阵的正交性可以看它是否符合以下条件: R T R = I R^TR=I R...

基于单片机的车灯智能控制系统设计与实现

标题:基于单片机的车灯智能控制系统设计与实现 内容:1.摘要 随着汽车行业的快速发展&#xff0c;车灯的智能化控制成为提升行车安全和驾驶体验的关键因素。本文旨在设计并实现一种基于单片机的车灯智能控制系统。采用单片机作为控制核心&#xff0c;结合光照传感器、雨滴传感器…...

机器学习第十一讲:标准化 → 把厘米和公斤单位统一成标准值

机器学习第十一讲&#xff1a;标准化 → 把厘米和公斤单位统一成标准值 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1a;超详细手把手指南 一、买菜…...

uni-app vue3版本打包h5后 页面跳转报错(uni[e] is not a function)

先看问题 解决方案 在HBuilderX项目中&#xff0c;若需在Web配置中显式关闭摇树优化&#xff08;Tree Shaking&#xff09;&#xff0c;可以通过以下步骤实现&#xff1a;首先&#xff0c;在配置中打开摇树优化&#xff0c;然后再将其关闭。这样操作后&#xff0c;配置文件中会…...

大二java第一面小厂(挂)

第一场&#xff1a; mybatis怎么防止数据转义。 Hutool用的那些你常用的方法。 springboot的常用注解。 redis的多级缓存。 websocket怎么实现的多人协作编辑功能。 怎么实现的分库分表。 mysql里面的各种操作&#xff0c;比如说分表怎么分&#xff0c;分页查询怎么用。 mybat…...

【Redis】缓存穿透、缓存雪崩、缓存击穿

1.缓存穿透 是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;导致请求直接穿透缓存到达数据库&#xff0c;给数据库带来压力的情况。 常见的解决方案有两种&#xff1a; 缓存空对象&#xff1a;实现简单&#xff0c;维护方便&am…...

双目云台摄像机:双摄安防功能全方位

双目云台摄像机是一种具有革命性设计的云台摄像机设备&#xff0c;其核心在于其独特的双摄像头配置。以下是对这种先进安防设备的详细介绍&#xff1a; 一、核心原理 双目云台摄像机的核心原理在于利用两个摄像头从不同角度捕捉同一场景&#xff0c;通过先进的算法计算两个图…...

告别数据僵尸!Redis实现自动清理过期键值对

在这个数据爆炸的时代&#xff0c;内存就像珍贵的土地资源&#xff0c;而Redis则是这片土地上的智能管家。它不仅能高效存储数据&#xff0c;还能像秋叶定时凋零般&#xff0c;让键值对在指定时间自动消失。今天&#xff0c;就让我们揭开这项"数据保鲜"技术的奥秘。 …...

web第三次课后作业--基于JDBC对mysql数据库的增删查改操作

一、工程搭建步骤 1.新建java项目&#xff0c;添加jdbc依赖 2.写java程序 3.添加mysql数据源&#xff0c;连接本地数据库 4.运行程序二、运行结果 三、代码 代码解析 加载数据驱动 try {Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptio…...

《P2345 [USACO04OPEN] MooFest G》

题目背景 P5094 [USACO04OPEN] MooFest G 加强版 题目描述 约翰的 n 头奶牛每年都会参加“哞哞大会”。 哞哞大会是奶牛界的盛事。集会上的活动很多&#xff0c;比如堆干草&#xff0c;跨栅栏&#xff0c;摸牛仔的屁股等等。 它们参加活动时会聚在一起&#xff0c;第 i 头…...

现代 Web 自动化测试框架对比:Playwright 与 Selenium 的深度剖析

现代 Web 自动化测试框架对比&#xff1a;Playwright 与 Selenium 的深度剖析 摘要&#xff1a;本文对 Playwright 与 Selenium 在开发适配性、使用难度、场景适用性及性能表现等方面进行了全面深入的对比分析。通过详细的技术实现细节阐述与实测数据支撑&#xff0c;为开发者…...

【网络协议】TCP、HTTP、MQTT 和 WebSocket 对比

从协议本质、工作原理、特点、应用场景等方面详细对比 TCP、HTTP、MQTT 和 WebSocket。 1. TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09; 本质 协议类型&#xff1a;传输层协议&#xff08;OSI模型第4层&#xff09;。核心功能&#x…...

Cython打包多层目录Python文件方法

为了使用Cython打包多层目录下的Python文件&#xff0c;并保持目录结构&#xff0c;请按照以下步骤操作&#xff1a; 步骤1&#xff1a;项目结构示例 假设项目结构如下&#xff1a; myproject/setup.pysrc/__init__.pymodule1.pysubdir/__init__.pymodule2.py步骤2&#xff…...

[数据结构]5. 栈-Stack

栈-Stack 1. 介绍2. 栈的实现2.1 基于链表的实现2.2 基于数组的实现 3. 栈操作CreateInitilizateDestoryPushPopTopEmptySize 1. 介绍 栈&#xff08;stack&#xff09; 是一种遵循先入后出逻辑的线性数据结构。顶部称为“栈顶”&#xff0c;底部称为“栈底”。把元素添加到栈…...

2020年下半年试题三:论云原生架构及其应用

论文库链接&#xff1a;系统架构设计师论文 论文题目 近年来&#xff0c;随着数字化转型不断深入&#xff0c;科技创新与业务发展不断融合&#xff0c;各行各业正在从大工业时代的固化范式进化成面向创新型组织与灵活型业务的崭新模式。在这一背景下&#xff0c;以容器盒微服务…...

基于Spring Boot + Vue的高校心理教育辅导系统

一、项目背景介绍 随着高校对学生心理健康教育的重视&#xff0c;传统的人工心理辅导与测评模式已经难以满足广大师生的个性化需求。为了提高心理服务的效率、便捷度和覆盖范围&#xff0c;本项目开发了一个高校心理教育辅导系统&#xff0c;集成心理评测、辅导预约、留言交流…...

JavaSwing之-JDialog

JavaSwing之-JDialog JDialog 是 Java Swing 中用于创建对话框窗口的容器类&#xff0c;继承自 Dialog 类&#xff08;AWT&#xff09;&#xff0c;常用于显示临时信息、获取用户输入或执行模态操作。它是 javax.swing.JDialog 包中的类。 与 JFrame 不同的是&#xff0c;JDia…...