构建高效可靠的消息队列系统:设计与实现



✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 
🎈🎈作者主页: 喔的嘛呀🎈🎈

目录

一、引言

二、设计目标

2.1、高可用性

1. 集群搭建

1.1 Docker Compose配置示例

2. 容错和恢复

2.1 异常检测与自动故障迁移

2.2 Spring Boot代码示例

3. 心跳检测

4. 优雅关闭

2.2、持久性

1. 生产者消息持久化

2. 队列的持久化

3. 消息队列的持久化

总结

2.3、低延迟

1. 异步消息传递

2. 批量消息发送

3. 消息序列化优化

4. 配置消息队列优化参数

总结

2.4、可伸缩性

1. 集群搭建

Docker Compose配置示例

2. 消费者的水平扩展

3. 动态调整资源配置

总结

2.5 顺序性

1. 单一队列实现顺序性

2. 消费者的单线程处理

3. 利用消息的消息头或属性

总结

2.6、监控与管理

1. 健康检查

2. 监控指标

3. 日志和错误处理

4. 运维工具

5. 定期维护

总结

三、架构设计

1. 组件设计

1.1 生产者

1.2 消费者

1.3 消息队列服务

1.4 管理与监控组件

2. 数据存储

3. 分布式一致性

总结



一、引言

消息队列是分布式系统中至关重要的组件之一,用于实现异步通信、解耦系统模块、缓解系统压力等。在本文中,我们将深入讨论如何设计一个高效可靠的消息队列系统,以满足各种应用场景的需求。

二、设计目标

在开始设计之前,我们首先要明确设计目标。一个理想的消息队列系统应该具备以下特性:

  1. 高可用性:系统应该能够容忍节点故障,保持高可用性。
  2. 持久性:消息在传递过程中不应该丢失,即使系统发生故障。
  3. 低延迟:消息传递应该保持低延迟,以满足实时性要求。
  4. 可伸缩性:系统应该能够处理不断增长的负载,支持水平扩展。
  5. 顺序性:对于需要保持顺序的消息,系统应该能够提供有序性保证。
  6. 监控与管理:提供有效的监控和管理手段,便于系统运维。

2.1、高可用性

1. 集群搭建

搭建RabbitMQ集群以确保高可用性。一个RabbitMQ集群由多个节点组成,每个节点分布在不同的物理服务器上。在节点之间进行数据同步,保证即使某个节点宕机,其他节点仍能提供服务。

1.1 Docker Compose配置示例
version: '3.7'
services:
  rabbitmq-node1:
    image: "rabbitmq:3.8-management"
    container_name: "rabbitmq-node1"
    ports:
      - "5672:5672"
      - "15672:15672"
    networks:
      - rabbitmq-network
    environment:
      RABBITMQ_ERLANG_COOKIE: "secret_cookie"
      RABBITMQ_NODENAME: "rabbit@node1"
      RABBITMQ_CLUSTER_NODE_NAME: "rabbit@node1"
      RABBITMQ_CLUSTER_NAME: "rabbit-cluster"
    restart: always

  rabbitmq-node2:
    image: "rabbitmq:3.8-management"
    container_name: "rabbitmq-node2"
    ports:
      - "5673:5672"
      - "15673:15672"
    networks:
      - rabbitmq-network
    environment:
      RABBITMQ_ERLANG_COOKIE: "secret_cookie"
      RABBITMQ_NODENAME: "rabbit@node2"
      RABBITMQ_CLUSTER_NODE_NAME: "rabbit@node2"
      RABBITMQ_CLUSTER_NAME: "rabbit-cluster"
    restart: always

networks:
  rabbitmq-network:

这是一个简单的Docker Compose配置,其中包含两个RabbitMQ节点,它们通过Erlang Cookie和集群名称连接到一起。

2. 容错和恢复

2.1 异常检测与自动故障迁移

在RabbitMQ中,可以使用 RabbitMQ Federation 插件来设置镜像队列,确保队列中的消息被复制到多个节点。如果某个节点发生故障,系统可以自动从其他节点获取数据,保证消息的可用性。

2.2 Spring Boot代码示例
@Configuration
public class RabbitMQConfig {

    @Bean
    public CachingConnectionFactory cachingConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("node1:5672,node2:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }
}

在Spring Boot中,配置 CachingConnectionFactory 来指定RabbitMQ节点的地址。通过设置多个节点的地址,Spring Boot将在节点之间建立连接,以实现高可用性。

3. 心跳检测

使用RabbitMQ提供的心跳检测机制,监测节点的健康状态。如果某个节点无响应,系统可以自动将其从集群中排除,并启用备用节点。

4. 优雅关闭

在系统关闭或者节点下线时,确保消息队列系统的优雅关闭。Spring Boot提供 @PreDestroy 注解,可以用于执行一些清理工作。

@Component
public class ShutdownHook {

    @PreDestroy
    public void onShutdown() {
        // 执行关闭前的清理工作,如释放资源等
        System.out.println("Shutting down gracefully...");
    }
}

通过搭建RabbitMQ集群、设置镜像队列、使用心跳检测和优雅关闭机制,我们可以构建一个具有高可用性的消息队列系统。在实际应用中,还需要根据业务场景和系统需求进行更详细的配置和调整,确保系统稳定可靠地运行。

2.2、持久性

确保消息的持久性是构建可靠消息队列系统的关键要素。在消息队列中,持久性通常涉及到两个方面:生产者将消息持久化到队列,以及消息队列本身的持久化。

以下是实现消息持久性的关键步骤和Java代码示例,使用RabbitMQ作为消息队列系统。

1. 生产者消息持久化

当生产者将消息发送到队列时,可以设置消息的持久性属性。这样,即使在消息被发送到队列但还未被处理时,系统发生故障,消息也不会丢失。

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageProducer {

    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendMessage(String message) {
        // 设置消息持久性
        amqpTemplate.convertAndSend("exchange", "routingKey", message, messagePostProcessor -> {
            messagePostProcessor.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            return messagePostProcessor;
        });
    }
}

在上述示例中,setDeliveryMode(MessageDeliveryMode.PERSISTENT) 将消息标记为持久性。这样,即使RabbitMQ节点在消息进入队列但尚未被消费者处理时发生故障,消息也会在节点重新启动后仍然存在。

2. 队列的持久化

为了确保即使RabbitMQ服务器重启,队列中的消息也不会丢失,我们需要将队列设置为持久化。

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueueConfiguration {

    @Bean
    public Queue exampleQueue() {
        // 设置队列持久性
        return new Queue("exampleQueue", true);
    }
}

在这个示例中,通过将 Queue 构造函数的第二个参数设置为 true,我们将队列标记为持久化的。这意味着队列的元数据和消息将在RabbitMQ服务器重启后继续存在。

3. 消息队列的持久化

确保RabbitMQ服务器本身的持久性也是重要的。通过在RabbitMQ的配置文件中设置 disk_free_limit 等参数,可以将消息队列的元数据和消息数据保存在持久化存储中,以防止数据丢失。

总结

通过设置生产者发送的消息和队列本身的持久性,以及确保消息队列系统本身的持久性,我们可以在系统发生故障时保证消息不会丢失。这对于构建可靠、稳定的消息队列系统至关重要,特别是在面对复杂分布式系统的挑战时。

2.3、低延迟

实现低延迟的消息传递对于满足实时性的要求至关重要。在构建消息队列系统时,我们可以采取一些策略和技术来降低消息传递的延迟。以下是一些关键点和Java代码示例,以使用RabbitMQ实现低延迟的消息传递。

1. 异步消息传递

使用异步消息传递机制,允许生产者发送消息而无需等待消费者的响应。这样可以在消息发送的同时继续进行其他操作,提高系统的并发性和响应速度。

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class AsyncMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendAsyncMessage(String message) {
        // 发送异步消息
        rabbitTemplate.convertAndSend("exchange", "routingKey", message);
        // 继续执行其他操作,而不必等待消息被消费
    }
}

在这个示例中,convertAndSend 是一个非阻塞的方法,它将消息发送到队列而不会等待确认。

2. 批量消息发送

将多个消息打包成一个批量发送,可以降低每个消息的传递时间。这对于需要频繁发送小量消息的场景特别有效。

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BatchMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendBatchMessage(List<String> messages) {
        // 批量发送消息
        for (String message : messages) {
            rabbitTemplate.convertAndSend("exchange", "routingKey", message);
        }
    }
}

在这个示例中,通过循环将多个消息发送到队列,可以减少每个消息的传递开销。

3. 消息序列化优化

选择高效的消息序列化方式,以降低消息的传递时间。例如,使用二进制序列化方式(如Google Protocol Buffers或MessagePack)相比于JSON或XML通常具有更高的性能。

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BinarySerializationMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    public void sendBinaryMessage(Object message) {
        // 使用二进制序列化方式发送消息
        byte[] serializedMessage = objectMapper.writeValueAsBytes(message);
        rabbitTemplate.convertAndSend("exchange", "routingKey", serializedMessage);
    }
}

在这个示例中,ObjectMapper 将对象序列化为字节数组,以便使用二进制格式发送。

4. 配置消息队列优化参数

通过配置消息队列的一些优化参数,可以降低传递消息的延迟。例如,设置队列的 x-message-ttl 参数,以定义消息的最大存活时间。

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueueConfiguration {

    @Bean
    public Queue exampleQueue() {
        // 设置队列的消息存活时间(毫秒)
        return new Queue("exampleQueue", true, false, false, ImmutableMap.of("x-message-ttl", 5000));
    }
}

在这个示例中,通过 ImmutableMap.of("x-message-ttl", 5000) 设置消息的最大存活时间为5秒。

总结

通过采用异步消息传递、批量消息发送、选择高效的消息序列化方式以及配置消息队列的优化参数,我们可以有效降低消息传递的延迟,满足实时性的要求。在实际应用中,需要根据具体场景和需求进行更详细的优化和调整。

2.4、可伸缩性

实现消息队列系统的可伸缩性是确保系统能够处理不断增长负载的关键。以下是一些关键点和Java代码示例,以使用RabbitMQ实现可伸缩的消息队列系统。

1. 集群搭建

构建消息队列系统的集群是实现可伸缩性的基础。通过在不同的节点上部署多个消息队列服务,可以有效地分摊负载并提高系统的整体吞吐量。

Docker Compose配置示例

version: '3.7'
services:
  rabbitmq-node1:
    image: "rabbitmq:3.8-management"
    container_name: "rabbitmq-node1"
    ports:
      - "5672:5672"
      - "15672:15672"
    networks:
      - rabbitmq-network
    environment:
      RABBITMQ_ERLANG_COOKIE: "secret_cookie"
      RABBITMQ_NODENAME: "rabbit@node1"
      RABBITMQ_CLUSTER_NODE_NAME: "rabbit@node1"
      RABBITMQ_CLUSTER_NAME: "rabbit-cluster"
    restart: always

  rabbitmq-node2:
    image: "rabbitmq:3.8-management"
    container_name: "rabbitmq-node2"
    ports:
      - "5673:5672"
      - "15673:15672"
    networks:
      - rabbitmq-network
    environment:
      RABBITMQ_ERLANG_COOKIE: "secret_cookie"
      RABBITMQ_NODENAME: "rabbit@node2"
      RABBITMQ_CLUSTER_NODE_NAME: "rabbit@node2"
      RABBITMQ_CLUSTER_NAME: "rabbit-cluster"
    restart: always

networks:
  rabbitmq-network:

通过在不同的节点上运行RabbitMQ实例,可以形成一个集群,以提高系统的可伸缩性。

2. 消费者的水平扩展

通过将消费者部署在多个实例上,实现对消费者的水平扩展。这样可以提高消息处理的并发性能。

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class Consumer {

    @RabbitListener(queues = "exampleQueue")
    public void handleMessage(String message) {
        // 处理接收到的消息
        System.out.println("Received message: " + message);
    }
}

在上述示例中,可以启动多个具有相同 @RabbitListener 注解的消费者实例,它们将同时监听同一个队列,实现消费者的水平扩展。

3. 动态调整资源配置

通过动态调整消息队列服务的资源配置,可以根据系统负载实时进行扩展或缩小。在Docker Compose配置中,可以使用scale指令启动多个节点实例。

services:
  rabbitmq-node1:
    # ...
    deploy:
      replicas: 3  # 指定节点数量
    # ...

  rabbitmq-node2:
    # ...
    deploy:
      replicas: 3  # 指定节点数量
    # ...

在实际应用中,根据系统监控数据和负载情况,动态调整实例数量和配置,以实现系统的弹性伸缩。

总结

通过构建消息队列系统的集群、实现消费者的水平扩展、以及动态调整资源配置,可以有效地提高系统的可伸缩性,使其能够处理不断增长的负载。在实际应用中,需要结合具体场景和需求,根据监控数据进行及时的调整和优化。

2.5 顺序性

保证消息的顺序性是在某些场景中非常重要的需求,例如在处理事务性消息或者处理业务逻辑依赖于消息顺序的情况。在消息队列系统中,有一些策略和技术可以用来确保消息的有序性。

以下是一些关键点和Java代码示例,以使用RabbitMQ实现有序性保证的消息队列系统。

1. 单一队列实现顺序性

将所有需要保持顺序的消息发送到同一个队列,通过单一队列来保证消息的顺序性。

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class OrderedMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendOrderedMessage(String message, int sequence) {
        // 发送有序消息,使用sequence作为routing key
        rabbitTemplate.convertAndSend("ordered_exchange", String.valueOf(sequence), message);
    }
}

在上述示例中,使用sequence作为消息的routing key,确保消息发送到同一个队列中。

2. 消费者的单线程处理

在消费者端,可以通过使用单线程来处理消息,确保消费者按照顺序处理消息。

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderedConsumer {

    @RabbitListener(queues = "ordered_queue")
    public void handleMessage(String message) {
        // 处理接收到的有序消息
        System.out.println("Received ordered message: " + message);
    }
}

在上述示例中,通过@RabbitListener注解,确保消息在同一个消费者实例的单线程中按照顺序处理。

3. 利用消息的消息头或属性

消息队列系统通常提供一些额外的消息头或属性来帮助实现有序性。例如,RabbitMQ提供了x-death属性,可以用于获取消息的死信信息,以此判断消息的处理状态。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderedConsumer {

    @RabbitListener(queues = "ordered_queue")
    public void handleMessage(Message message) {
        // 获取消息的死信信息
        Map<String, Object> deathHeaders = message.getMessageProperties().getHeaders();
        // 根据死信信息判断消息的处理状态
        // ...
    }
}

在实际应用中,可以根据具体的需求和场景选择合适的方式来实现有序性保证。

总结

通过将有序消息发送到同一个队列,使用单线程处理消费者,或者利用消息的消息头或属性,我们可以在消息队列系统中实现有序性保证。在选择策略时,需要根据实际需求和系统规模综合考虑。

2.6、监控与管理

在构建消息队列系统时,提供有效的监控和管理手段对于系统的运维至关重要。这涉及到监控系统的健康状况、性能指标、以及执行维护和管理操作的能力。以下是一些建议和Java代码示例,使用RabbitMQ为例,来实现监控与管理功能。

1. 健康检查

实现一个简单的健康检查接口,供运维人员使用,用于检查消息队列系统是否正常运行。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HealthCheckController {

    @GetMapping("/health")
    public String healthCheck() {
        // 检查消息队列系统的健康状况
        // ...

        return "OK";
    }
}

在上述示例中,/health 路径是一个用于健康检查的端点,返回 "OK" 表示系统正常。

2. 监控指标

使用监控工具,例如Prometheus或者Spring Boot Actuator,来收集和暴露消息队列系统的性能指标。

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

@Component
@Endpoint(id = "rabbitmq")
public class RabbitMQMetricsEndpoint {

    @ReadOperation
    public RabbitMQMetrics getMetrics() {
        // 获取RabbitMQ相关的性能指标
        // ...

        return new RabbitMQMetrics(/* 指标数据 */);
    }
}

在上述示例中,通过创建一个自定义的Actuator端点,可以将RabbitMQ的性能指标暴露出来,方便监控。

3. 日志和错误处理

配置合适的日志记录,确保错误和异常情况能够被及时捕获和记录。使用工具或系统来集中收集日志信息,以便于分析和排查问题。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler;

public class CustomErrorHandler extends ConditionalRejectingErrorHandler {

    private static final Logger logger = LoggerFactory.getLogger(CustomErrorHandler.class);

    @Override
    public void handleError(Throwable t) {
        // 记录错误日志
        logger.error("Error in RabbitMQ message processing", t);
        super.handleError(t);
    }
}

在上述示例中,通过自定义错误处理器,可以在消息处理发生错误时记录相关的日志信息。

4. 运维工具

使用专业的运维工具,例如RabbitMQ Management Plugin,可以通过Web界面轻松地监控和管理RabbitMQ。通过提供友好的用户界面,运维人员可以更方便地查看队列状态、执行操作等。

5. 定期维护

定期执行系统维护操作,例如清理过期的消息、检查节点健康状态、更新系统配置等。可以通过定时任务或者集成现有的调度工具来执行这些操作。

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class MaintenanceTask {

    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
    public void performMaintenance() {
        // 执行系统维护操作
        // ...
    }
}

在上述示例中,通过使用Spring的定时任务,可以定期执行维护操作。

总结

通过实现健康检查、暴露监控指标、配置日志和错误处理、使用运维工具以及定期维护等手段,可以为消息队列系统提供有效的监控和管理手段,以便于系统运维。在实际应用中,根据具体需求选择合适的工具和策略。

三、架构设计

1. 组件设计

1.1 生产者

生产者负责将消息发送到消息队列系统中。在设计中,生产者可以通过REST API或者消息协议(如AMQP、Kafka协议)与消息队列进行通信。

1.2 消费者

消费者从消息队列中订阅并消费消息。消费者可以通过订阅特定的主题或队列,以接收感兴趣的消息。

1.3 消息队列服务

消息队列服务是核心组件,负责存储和分发消息。它包含多个节点以确保高可用性,并提供消息的持久性保证。

1.4 管理与监控组件

为了方便系统运维,设计一个管理与监控组件,用于监视消息队列的状态、执行维护操作,并提供合适的API供运维人员使用。

2. 数据存储

消息队列的数据存储通常采用高性能的存储引擎,支持快速读写操作。对于持久性要求高的系统,可以使用分布式文件系统或者分布式数据库。

3. 分布式一致性

保证分布式系统的一致性是设计中的难点之一。采用分布式事务、选举算法和副本机制来确保系统在节点故障时依然保持一致性。

总结

设计一个高效可靠的消息队列系统需要综合考虑架构、一致性、性能和可维护性等多个方面。上述代码示例使用了Spring Boot和RabbitMQ,但具体的技术选型可以根据项目需求和团队熟悉度来定。在实际应用中,还需考虑安全性、容灾性、监控等方面的问题,以确保系统能够稳定、可靠地运行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MACBOOK PRO M2 MAX 安装Stable Diffusion及文生图实例

以前偶尔会使用Midjourney生成一些图片&#xff0c;现在使用的头像就是当时花钱在Midjourney上生成的。前段时间从某鱼上拍了一台性价比还不错的macbook&#xff0c;想着不如自己部署Stable Diffusion&#xff08;以下简称SD&#xff09;尝试一下。 网上有很多教程&#xff0c…

数组的内存执行原理

一.Java内存分配介绍 JVM虚拟机会在内存中执行程序 java内存分配介绍 方法区&#xff0c;栈&#xff0c;堆 首先将编译过后的.class文件送入方法区中。当类开始运行时将方法调入栈内存中&#xff0c;变量也是属于方法的&#xff0c;因此同方法一起进入栈内存中。当main方法要…

日期问题---算法精讲

前言 今天讲讲日期问题&#xff0c;所谓日期问题&#xff0c;在蓝桥杯中出现众多&#xff0c;但是解法比较固定。 一般有判断日期合法性&#xff0c;判断是否闰年&#xff0c;判断日期的特殊形式&#xff08;回文或abababab型等&#xff09; 目录 例题 题2 题三 总结 …

人工智能|机器学习——K-means系列聚类算法k-means/ k-modes/ k-prototypes/ ......(划分聚类)

1.k-means聚类 1.1.算法简介 K-Means算法又称K均值算法&#xff0c;属于聚类&#xff08;clustering&#xff09;算法的一种&#xff0c;是应用最广泛的聚类算法之一。所谓聚类&#xff0c;即根据相似性原则&#xff0c;将具有较高相似度的数据对象划分至同一类簇&#xff0c;…

CentOS 7.6安装部署Seafile服务器

今天飞飞和你们分享CentOS 7.6上安装基于MySQL/MariaDB的Seafile服务器的方法&#xff0c;包括下载和安装7.0.5版本、配置数据库、启动服务器等步骤。安装成功后&#xff0c;需要通过nginx反向代理才能访问seafile服务。 通过预编译好的安装包来安装并运行基于 MySQL/MariaDB …

Day27:安全开发-PHP应用TP框架路由访问对象操作内置过滤绕过核心漏洞

目录 TP框架-开发-配置架构&路由&MVC模型 TP框架-安全-不安全写法&版本过滤绕过 思维导图 PHP知识点 功能&#xff1a;新闻列表&#xff0c;会员中心&#xff0c;资源下载&#xff0c;留言版&#xff0c;后台模块&#xff0c;模版引用&#xff0c;框架开发等 技…

网络触手获取天气数据存入mysql 项目

首先这个案例不一定能直接拿来用&#xff0c;虽然我觉得可以但是里面肯定有一些我没考虑到的地方。 有问题评论或者私信我&#xff1a; 这个案例适合我这种学生小白 获取天气数据网址&#xff1a; https://lishi.tianqi.com/xianyang/202201.html 网络触手获取天气数据代码直…

Svg Flow Editor 原生svg流程图编辑器(二)

系列文章 Svg Flow Editor 原生svg流程图编辑器&#xff08;一&#xff09; 说明 这项目也是我第一次写TS代码哈&#xff0c;现在还被绕在类型中头昏脑胀&#xff0c;更新可能会慢点&#xff0c;大家见谅~ 目前实现的功能&#xff1a;1. 元件的创建、移动、形变&#xff1b;2…

运动想象 (MI) 迁移学习系列 (3) : MSFT

运动想象迁移学习系列:MSFT 0. 引言1. 主要贡献2. 数据增强方法3. 基于度量的空间滤波转换器3.1 空间过滤3.2 脑电图ViT3.2.1 变压器编码器层3.2.2 基于度量的损失函数 4. 实验结果4.1 消融实验4.2 基线任务对比4.3 跨主题 5. 总结欢迎来稿 论文地址&#xff1a;https://www.s…

深入浅出计算机网络 day.1 概论② 因特网概述

当你回头看的时候&#xff0c;你会发现自己走了一段&#xff0c;自己都没想到的路 —— 24.3.9 内容概述 01.网络、互连&#xff08;联&#xff09;网与因特网的区别与联系 02.因特网简介 一、网络、互连&#xff08;联&#xff09;网与因特网的区别与联系 1.若干节点和链路互连…

Java 客户端向服务端上传文件(TCP通信)

一、实验内容 编写一个客户端向服务端上传文件的程序&#xff0c;要求使用TCP通信的的知识&#xff0c;完成将本地机器输入的路径下的文件上传到D盘中名称为upload的文件夹中。并把客户端的IP地址加上count标识作为上传后文件的文件名&#xff0c;即IP&#xff08;count&#…

excel统计分析——嵌套设计

参考资料&#xff1a;生物统计学&#xff0c;巢式嵌套设计的方差分析 嵌套设计&#xff08;nested design&#xff09;也称为系统分组设计或巢式设计&#xff0c;是把试验空间逐级向低层次划分的试验设计方法。与裂区设计相似&#xff0c;先按一级因素设计试验&#xff0c;然后…

Linux网络套接字之预备知识

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目录 一、预备知识 1.理解源IP地址和目的IP地址 …

真实案例分享:MOS管电源开关电路,遇到上电冲击电流超标

做硬件&#xff0c;堆经验。 分享一个案例&#xff1a;MOS管电源开关电路&#xff0c;遇到上电冲击电流超标&#xff0c;怎么解决的呢&#xff1f; 下面是正文部分。 —— 正文 —— 最近有一颗用了挺久的MOSFET发了停产通知&#xff0c;供应链部门找到我们研发部门&#xff0c…

RabbitMQ发布确认高级版

1.前言 在生产环境中由于一些不明原因&#xff0c;导致 RabbitMQ 重启&#xff0c;在 RabbitMQ 重启期间生产者消息投递失败&#xff0c; 导致消息丢失&#xff0c;需要手动处理和恢复。于是&#xff0c;我们开始思考&#xff0c;如何才能进行 RabbitMQ 的消息可靠投递呢&…

C++——string模拟实现

前言&#xff1a;上篇文章我们对string类及其常用的接口方法的使用进行了分享&#xff0c;这篇文章将着重进行对这些常用的接口方法的内部细节进行分享和模拟实现。 目录 一.基础框架 二.遍历字符串 1.[]运算符重载 2.迭代器 3.范围for 三.常用方法 1.增加 2.删除 3.调…

spring boot 2.4.x 之前版本(对应spring-cloud-openfeign 3.0.0之前版本)feign请求异常逻辑

目录 feign SynchronousMethodHandler 第一部分 第二部分 第三部分 spring-cloud-openfeign LoadBalancerFeignClient ribbon AbstractLoadBalancerAwareClient 在之前写的文章配置基础上 https://blog.csdn.net/zlpzlpzyd/article/details/136060312 因为从 spring …

Excel F4键的作用

目录 一. 单元格相对/绝对引用转换二. 重复上一步操作 一. 单元格相对/绝对引用转换 ⏹ 使用F4键 如下图所示&#xff0c;B1单元格引用了A1单元格的内容。此时是使用相对引用&#xff0c;可以按下键盘上的F4键进行相对引用和绝对引用的转换。 二. 重复上一步操作 ⏹添加或删除…

【Python】装饰器函数

专栏文章索引&#xff1a;Python 原文章&#xff1a;装饰器函数基础_装饰函数-CSDN博客 目录 1. 学习装饰器的基础 2.最简单的装饰器 3.闭包函数装饰器 4.装饰器将传入的函数中的值大写 5. 装饰器的好处 6. 多个装饰器的执行顺序 7. 装饰器传递参数 8. 结语 1. 学习装饰…

c++中string的模拟实现(超详细!!!)

1.string的成员变量、&#xff08;拷贝&#xff09;构造、析构函数 1.1.成员变量 private:char* _str;size_t _size; //string中有效字符个数size_t _capacity; //string中能存储有效字符个数的大小 1.2&#xff08;拷贝&#xff09;构造函数 //构造函数string(const char* …