RabbitMQ 可靠性投递

文章目录

  • 前言
  • 一、RabbitMQ自带机制
    • 1、生产者发送消息
      • 注意
      • 1.1、事务(Transactions)
      • 1.2、发布确认(Publisher Confirms)
        • 1.2.1、同步
        • 1.2.2、异步
    • 2、消息路由机制
      • 2.1、使用备份交换机(Alternate Exchanges)
      • 2.2、启用消息的确认回调(Return Callbacks)
      • 2.3、配置死信交换机(Dead Letter Exchanges)
    • 3、消息存储持久化机制
      • 3.1、队列持久化(Durable Queue)
      • 3.2、消息持久化(Persistent Message)
      • 3.3、集群部署
    • 4、消费者消费消息
  • 二、业务保证
    • 1、最终一致性
    • 2、监控和告警


前言

RabbitMQ 是一个流行的消息队列系统,用于在分布式系统中传递消息。其中一个重要特性是其可靠性投递(Reliable Message Delivery),保证消息在队列和消费者之间可靠的传递和处理。


一、RabbitMQ自带机制

RabbitMQ 的架构图
在这里插入图片描述

从架构图中,我们可以发现,消息投递的关键步骤在于如下四点
在这里插入图片描述

  • 1.生产者发送消息
  • 2.消息路由机制
  • 3.消息存储持久化机制
  • 4.消费者消费消息

接下来我们一步一步进行分析

1、生产者发送消息

当网络中断或者节点不存在等,均有可能导致生产者发送消息失败,对于失败,可以通过如下机制进行处理

  • 事务(Transactions)
  • 发布确认(Publisher Confirms)

事务(Transactions)和发布确认(Publisher Confirms)是两种确保消息持久性和可靠性的方法。

注意

事务提供了一种全有或全无的机制,但通常不建议在生产环境中使用,因为它们会显著降低性能。发布确认则提供了更轻量级的解决方案,具有更高的性能和灵活性。

1.1、事务(Transactions)

事务的工作原理

  • 事务机制确保一组消息的发送要么全部成功,要么全部失败。如果提交事务失败,所有消息都会回滚,确保数据一致性。

使用方法

  • 启动事务:在信道上启动事务模式。
  • 提交事务:成功时提交所有消息。
  • 回滚事务:发生错误时回滚所有消息。

示例

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;public class RabbitMQTransaction {private final static String QUEUE_NAME = "transaction_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);try {// 启动事务模式channel.txSelect();for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}// 提交事务channel.txCommit();System.out.println("Transaction committed");} catch (Exception e) {System.out.println("Transaction failed: " + e.getMessage());// 回滚事务channel.txRollback();System.out.println("Transaction rolled back");}}}
}

1.2、发布确认(Publisher Confirms)

1.2.1、同步

相较于事务,发布确认(Publisher Confirms)是更为推荐的方式,因为它可以提供类似的可靠性并且具有更好的性能表现:

  • 发布:使用 channel.confirmSelect() 启用发布确认模式。
  • 回调:在发布消息后调用 channel.waitForConfirmsOrDie 方法等待确认,或捕获 Exception 进行错误处理。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConfirmCallback;public class RabbitMQPublishConfirm {private final static String QUEUE_NAME = "confirm_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);// 启用发布确认模式channel.confirmSelect();// 发布消息for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}// 确认所有发布的消息// 批量确认结果, ACK 如果是 Multiple=True, 代表 ACK 里面的 Delivery-Tag 之前的消息都被确认了// 比如 5 条消息可能只收到 1 个 ACK, 也可能收到 2 个(抓包才看得到)// 直到所有信息都发布, 只要有一个未被 Broker 确认就会 Exceptionchannel.waitForConfirmsOrDie(5000);System.out.println("All messages confirmed");} catch (Exception e) {System.err.println("Message publishing failed: " + e.getMessage());}}
}
1.2.2、异步

异步确认模式(Asynchronous Confirmations)在发布确认模式的基础上提供了更高效和灵活的消息确认机制。相比于同步发布确认,异步模式允许发布者继续发送消息而不必等待每条消息的确认。这种模式更适合高吞吐量的生产环境。以下是实现异步确认模式的详细步骤和示例代码:

  • 建立连接和信道:与RabbitMQ服务器建立连接并创建信道。
  • 启用发布确认模式:使用 channel.confirmSelect() 方法。
  • 设置确认回调(Confirms Callback):定义消息确认和未确认的回调方法。
    • ConfirmCallback: 用于确认成功的回调。
    • ConfirmListener: 用于设定成功和失败的回调。
  • 发送消息:发布者继续发送消息,不需要等待确认。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConfirmCallback;public class AsyncConfirmPublisher {private static final String QUEUE_NAME = "async_confirm_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);// 启用发布确认模式channel.confirmSelect();// 设置确认和未确认的回调处理事件ConfirmCallback ackCallback = (deliveryTag, multiple) -> {System.out.println("Message ACKed with delivery tag: " + deliveryTag + ", multiple: " + multiple);};ConfirmCallback nackCallback = (deliveryTag, multiple) -> {System.err.println("Message NACKed with delivery tag: " + deliveryTag + ", multiple: " + multiple);};channel.addConfirmListener(ackCallback, nackCallback);// 发布消息for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}}}
}

2、消息路由机制

当 routingKey 错误,或者队列不存在的时候,就会出现无法路由,导致消息投递失败,解决方案

  • 使用备份交换机(Alternate Exchanges):如果消息无法路由到指定的交换机,RabbitMQ 可以将消息路由到一个备用交换机。
  • 启用消息的确认回调(Return Callbacks):当消息无法路由到任何队列时,可以使用回调函数捕获并处理这些未被路由的消息。
  • 配置死信交换机(Dead Letter Exchanges):当消息在队列中无法被消费或出现错误时,可将消息转发到死信交换机进行之后处理。

2.1、使用备份交换机(Alternate Exchanges)

备份交换机可以防止消息丢失,如果消息无法路由到主交换机,会被备份交换机存储。

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";private static final String ALTERNATE_EXCHANGE = "alternate_exchange";private static final String ALTERNATE_QUEUE = "alternate_queue";@Beanpublic ConnectionFactory connectionFactory() {// Configuration connection factory, assuming default settingsreturn new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback(returnCallback);return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return ExchangeBuilder.directExchange(PRIMARY_EXCHANGE).durable(true).alternate(ALTERNATE_EXCHANGE).build();}@Beanpublic DirectExchange alternateExchange() {return new DirectExchange(ALTERNATE_EXCHANGE);}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).build();}@Beanpublic Queue alternateQueue() {return new Queue(ALTERNATE_QUEUE);}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}@Beanpublic Binding bindingAlternate() {return BindingBuilder.bind(alternateQueue()).to(alternateExchange()).with("");}private final RabbitTemplate.ReturnCallback returnCallback = (message, replyCode, replyText,exchange, routingKey) -> {// Handle undeliverable messageSystem.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);};
}

2.2、启用消息的确认回调(Return Callbacks)

启用消息的确认回调,当消息无法路由到任何队列时,可以使用回调函数捕获并处理这些未被路由的消息。

import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";@Beanpublic ConnectionFactory connectionFactory() {return new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {// 错误处理逻辑System.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);});return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return ExchangeBuilder.directExchange(PRIMARY_EXCHANGE).durable(true).build();}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).build();}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}
}

2.3、配置死信交换机(Dead Letter Exchanges)

消息在队列中无法被消费或出现错误时,可将其转发到死信交换机进行特定处理。

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";private static final String DLX_EXCHANGE = "dlx_exchange";private static final String DLX_QUEUE = "dlx_queue";@Beanpublic ConnectionFactory connectionFactory() {return new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {// 错误处理逻辑System.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);});return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return new DirectExchange(PRIMARY_EXCHANGE);}@Beanpublic DirectExchange dlxExchange() {return new DirectExchange(DLX_EXCHANGE);}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).withArgument("x-dead-letter-exchange", DLX_EXCHANGE).build();}@Beanpublic Queue dlxQueue() {return QueueBuilder.durable(DLX_QUEUE).build();}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}@Beanpublic Binding bindingDLX() {return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with("#");}
}

3、消息存储持久化机制

如果消息没有持久化,当RabbitMQ服务重启、节点故障等情况下就会丢失消息,解决方案

3.1、队列持久化(Durable Queue)

创建队列时将其设置为持久化

channel.queueDeclare("queue_name", durable=True)

3.2、消息持久化(Persistent Message)

发送消息时将其标记为持久化

channel.basicPublish(exchange='', routingKey='queue_name', body=msg, properties=pika.BasicProperties(delivery_mode=2,))

3.3、集群部署

保证节点的高可用

4、消费者消费消息

在使用 RabbitMQ 作为消息队列系统时,消费者确认机制(Consumer Acknowledge)对于确保消息可靠消费非常重要。当消费者从队列中接收到消息时,必须明确确认消息已被成功处理。这种机制不仅防止消息丢失,还避免了消息重复消费的问题。
RabbitMQ 提供了两种主要的消息确认机制:

  • 手动确认(Manual Acknowledgement):消费者显式地向 RabbitMQ 发送确认消息,表明消息已被成功处理。
  • 自动确认(Automatic Acknowledgement):RabbitMQ 在消息被发送给消费者后立即认为消息已经成功处理,无需等待显式确认。(默认)
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.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String EXCHANGE_NAME = "direct_exchange";private static final String QUEUE_NAME = "example_queue";@Beanpublic DirectExchange directExchange() {return new DirectExchange(EXCHANGE_NAME);}@Beanpublic Queue queue() {return new Queue(QUEUE_NAME, true);}@Beanpublic Binding binding(Queue queue, DirectExchange exchange) {return BindingBuilder.bind(queue).to(exchange).with("routing_key");}@Beanpublic SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.setQueueNames(QUEUE_NAME);container.setMessageListener(listenerAdapter);// 自动确认 AcknowledgeMode.AUTO// 手动确认 AcknowledgeMode.MANUALcontainer.setAcknowledgeMode(org.springframework.amqp.core.AcknowledgeMode.MANUAL); return container;}@Beanpublic MessageListenerAdapter listenerAdapter(Consumer consumer) {return new MessageListenerAdapter(consumer, "consumeMessage");}
}

如果是手动确认,消费者处理消息的时候实现手动确认机制:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;@Component
public class Consumer implements ChannelAwareMessageListener {@Overridepublic void onMessage(Message message, Channel channel) throws Exception {try {// 处理消息逻辑String body = new String(message.getBody());System.out.println("Received message: " + body);// 手动确认消息channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 消息处理失败,拒绝消息并重新入队channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);System.err.println("Failed to process message: " + e.getMessage());}}
}

二、业务保证

1、最终一致性

  • 消息持久化处理:在发出消息之前,将消息存储到持久化存储设备,如数据库。 并使用消息状态进行追踪,每个状态表示消息的处理进度。
  • 补偿机制:根据超时和失败记录进行消息补偿。
    • 怎么触发重发(定时任务)
    • 多久触发一次(参考业务属性)
    • 触发多少次(参考业务属性)
  • 幂等性:确保消费者在处理消息时是幂等的,即多次处理不会导致副作用。

通过以上的方案结合,保证消息的最终一致性

2、监控和告警

建立监控系统,及时发现和处理异常情况,然后及时作出相应,增加客户的良好体验
例如:
使用 Prometheus 和 Grafana 对消息队列和数据库进行监控,及时发现并告警异常情况。
也可以结合业务属性,自己创建一套简单的监控系统。

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

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

相关文章

番外02:前端八股文面试题-CSS篇

一&#xff1a;CSS基础 1&#xff1a;CSS选择器及其优先级 2&#xff1a;display的属性值及其作用 属性值作用none元素不显示&#xff0c;并且会从文档流中移除block块类型&#xff0c;默认元素为父元素宽度&#xff0c;可设置宽高&#xff0c;换行显示inline行内元素类型&a…

如何在C++ QT 程序中集成cef3开源浏览器组件去显示网页?

文章目录 1. **准备工作**1.1 下载CEF31.2 配置Qt项目 2. **集成CEF3到Qt窗口**2.1 创建Qt窗口容器2.2 初始化CEF3 3. **处理CEF3消息循环**4. **处理多进程架构**5. **完整代码示例**main.cpp 6. **常见问题**6.1 黑屏问题6.2 窗口嵌入失败6.3 多进程调试 7.**Github源码参考*…

【实用技能】如何借助3D文档控件Aspose.3D, 在Java中无缝制作 3D 球体

概述 创建 3D 球体是 3D 图形设计的一个基本方面。无论您是在开发游戏、模拟还是可视化&#xff0c;无缝创建 3D 球体模型的能力都至关重要。Aspose.3D通过提供强大的 3D 图形 SDK 在各个行业中发挥着重要作用。它允许开发人员轻松创建、操作和转换 3D 模型。此 SDK 对于希望将…

【Leetcode 热题 100】169. 多数元素

问题背景 给定一个大小为 n n n 的数组 n u m s nums nums&#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n / 2 ⌋ \lfloor n/2 \rfloor ⌊n/2⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 数据约束 n n u…

Docker build时apt update失败

配置好dockerfile后&#xff0c;编译镜像docker build -t my-debian .报错&#xff1a; E: Release file for http://mirrors.org/debian/dists/bookworm-updates/InRelease is not valid yet (invalid for another 3h 15min 21s). Updates for this repository will not be a…

MySql数据库SQL编写规范注意事项

MySQL数据库SQL编写规范对于提高代码可读性、增强代码维护性、优化查询性能、减少错误发生、促进标准化和团队协作以及提升开发效率等方面都具有重要意义。因此&#xff0c;在开发过程中应严格遵守SQL编写规范&#xff0c;以确保代码的质量和效率。 以下是 MySQL 数据库 SQL 编…

Jenkins 使用教程:从入门到精通

在软件开发的复杂流程中&#xff0c;持续集成与持续交付&#xff08;CI/CD&#xff09;是提升开发效率和保障软件质量的核心实践。Jenkins 作为一款备受欢迎的开源自动化服务器&#xff0c;在 CI/CD 流程中发挥着举足轻重的作用。本文将深入、详细地介绍 Jenkins 的使用方法&am…

通过k8s请求selfsubjectrulesreviews查询权限

当前是通过kubelet进行查询 curl --cacert /etc/kubernetes/pki/ca.crt \ --cert /var/lib/kubelet/pki/kubelet-client-current.pem \ --key /var/lib/kubelet/pki/kubelet-client-current.pem \ -d - \ -H "Content-Type: application/json" \ -H Accept: applicat…

C语言基础系列【3】VSCode使用

前面我们提到过VSCode有多么的好用&#xff0c;本文主要介绍如何使用VSCode编译运行C语言代码。 安装 首先去官网&#xff08;https://code.visualstudio.com/&#xff09;下载安装包&#xff0c;点击Download for Windows 获取安装包后&#xff0c;一路点击Next就可以。 配…

windows安装WSL完整指南

本文首先介绍WSL&#xff0c;然后一步一步安装WSL及Ubuntu系统&#xff0c;最后讲解如何在两个系统之间访问和共享文件信息。通过学习该完整指南&#xff0c;能帮助你快速安装WSL&#xff0c;解决安装和使用过程中的常见问题。 理解WSL&#xff08;Windows Subsystem for Linux…

doris:MySQL 兼容性

Doris 高度兼容 MySQL 语法&#xff0c;支持标准 SQL。但是 Doris 与 MySQL 还是有很多不同的地方&#xff0c;下面给出了它们的差异点介绍。 数据类型​ 数字类型​ 类型MySQLDorisBoolean- 支持 - 范围&#xff1a;0 代表 false&#xff0c;1 代表 true- 支持 - 关键字&am…

【LeetCode 刷题】贪心算法(4)-区间问题

此博客为《代码随想录》贪心算法章节的学习笔记&#xff0c;主要内容为贪心算法区间问题的相关题目解析。 文章目录 55. 跳跃游戏45. 跳跃游戏 II452. 用最少数量的箭引爆气球435. 无重叠区间763. 划分字母区间56. 合并区间 55. 跳跃游戏 题目链接 class Solution:def canJu…

苹果公司宣布正式开源 Xcode 引擎 Swift Build145

2025 年 2 月 1 日&#xff0c;苹果公司宣布正式开源 Xcode 引擎 Swift Build145。 Swift 是苹果公司于 2014 年推出的一种开源编程语言&#xff0c;用于开发 iOS、iPadOS、macOS、watchOS 和 tvOS 等平台的应用程序。 发展历程 诞生&#xff1a;2014 年&#xff0c;苹果在全球…

PID 算法简介(C语言)

一、简介: PID是比例、积分、微分三个环节的组合,用来进行反馈控制。每个部分都有对应的系数,也就是Kp、Ki、Kd。PID 算法实现这三个部分的计算,然后综合起来得到控制输出。 二、PID控制器结构体: PID控制器结构体:包含PID参数(Kp, Ki, Kd);存储积分项和上一次误差;…

123,【7】 buuctf web [极客大挑战 2019]Secret File

进入靶场 太熟悉了&#xff0c;有种回家的感觉 查看源代码&#xff0c;发现一个紫色文件 点下看看 点secret 信息被隐藏了 要么源代码&#xff0c;要么抓包 源代码没有&#xff0c;抓包 自己点击时只能看到1和3处的文件&#xff0c;点击1后直接跳转3&#xff0c;根本不出…

HTTP协议学习大纲

第一阶段&#xff1a;HTTP基础概念 互联网与Web基础 理解Web工作原理&#xff1a;客户端-服务器模型URL与URI的结构及区别端口、协议、域名概念 HTTP协议概览 HTTP的作用与特点&#xff08;无状态、无连接、可扩展&#xff09;HTTP协议版本演进&#xff08;0.9 → 1.0 → 1.1 …

Formality:时序变换(五)(寄存器复制)

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 一、引言 时序变换在Design Compiler的首次综合和增量综合中都可能发生&#xff0c;它们包括&#xff1a;时钟门控(Clock Gating)、寄存器合并(Register Merging)、…

我使用deepseek高效学习-分析外文网站Cron定时执行任务

最近在spring框架中 设置定时任务&#xff0c;有的末尾是星号有的是问号&#xff0c;有的是6位&#xff0c;有的是7位。就这个机会总结下cron表达式的使用&#xff0c;综合源代码中的crontab地址翻译分析&#xff0c;结合最近超爆的deepseek 提高学习效率&#xff0c;归纳总结出…

BurpSuite抓包与HTTP基础

文章目录 前言一、BurpSuite1.BurpSuite简介2.BurpSuite安装教程(1)BurpSuite安装与激活(2)安装 https 证书 3.BurpSuite使用4.BurpSuite资料 二、图解HTTP1.HTTP基础知识2.HTTP客户端请求消息3.HTTP服务端响应消息4.HTTP部分请求方法理解5.HTTPS与HTTP 总结 前言 在网络安全和…

华为交换机堆叠配置

一、CSS堆叠集群配置&#xff08;框式交换机&#xff09; 1、通过集群卡连接方式组建集群 [SwitchA] set css mode css-card \\配置集群卡连接方式 [SwitchA] set css id 1 \\配置成员交换机的集群ID(缺省值为1) [SwitchA] set css priority 100 \\配…