科普文:微服务之Spring Cloud Alibaba消息队列组件RocketMQ工作原理
概叙
本文探讨 RocketMQ 的事务消息原理,并从源码角度进行分析,以及事务消息适合什么场景,使用事务消息需要注意哪些事项。
同时详细介绍RocketMQ 事务消息的基本流程,并通过源码分析揭示了其内部实现原理,尽管事务消息增加了系统的复杂性,但在需要保证消息一致性的场景中,它仍然是一种非常有效的解决方案,比如资金转账、订单处理、分布式事务、库存管理等场景。
什么是事务消息
事务消息是为了保证分布式系统中消息的一致性而引入的一种消息类型。事务消息允许消息发送方在发送消息后,进行本地事务操作,并根据本地事务的执行结果来决定消息的最终状态(提交或回滚)。
RocketMQ 事务消息的优缺点
优点
-
保证消息一致性:通过事务消息,RocketMQ 能够保证分布式系统中消息的一致性,避免数据不一致问题。
-
高性能:RocketMQ 的事务消息性能较高,能够满足高并发场景的需求。
-
易用性:RocketMQ 提供了简单易用的 API,使得开发者能够方便地使用事务消息。
缺点
-
复杂性:事务消息的引入增加了系统的复杂性,开发者需要处理事务状态回查等问题。
-
时延:事务消息的处理涉及
half
消息、回查等操作,可能会增加消息的时延。
事务消息适用场景
资金转账
在金融系统中,资金转账需要确保资金的一致性和安全性。例如,从账户 A 转账到账户 B,必须确保 A 的金额减少和 B 的金额增加是一个原子操作。使用事务消息可以保证在转账过程中,如果任何一个步骤失败,整个操作都会回滚,确保数据一致性。
订单处理
在电子商务系统中,订单处理通常涉及多个步骤,例如创建订单、扣减库存、生成支付记录等。这些步骤需要保证一致性。使用事务消息可以确保如果某一步操作失败,整个订单处理过程可以回滚,避免数据不一致。
分布式事务
在微服务架构中,分布式事务是一个常见的挑战。多个微服务之间的操作需要协调一致,事务消息可以作为一种分布式事务解决方案,确保各个微服务之间的数据一致性。
库存管理
在库存管理系统中,库存的增减操作需要保证一致性。例如,用户下单后需要扣减库存,使用事务消息可以确保在扣减库存失败时,订单状态不会被错误更新。
事务消息注意事项
确保本地事务的幂等性
在分布式系统中,本地事务操作可能会被多次执行。例如,在事务状态回查时,Broker 可能会多次检查本地事务状态。因此,确保本地事务操作的幂等性非常重要。幂等性可以确保多次执行相同的操作不会产生副作用。
设置合理的超时时间
事务消息的处理涉及half
消息、提交或回滚请求以及事务状态回查。设置合理的超时时间可以避免长时间等待,影响系统性能。超时时间应根据实际业务需求和系统性能进行调整。
处理事务状态回查
事务状态回查是事务消息的重要机制。当 Broker 在规定时间内没有收到提交或回滚请求时,会主动发起事务状态回查。开发者需要实现 TransactionCheckListener 接口,并在 checkLocalTransactionState 方法中处理回查逻辑,确保能够正确返回事务状态。
监控和日志
监控和日志是确保事务消息系统稳定运行的重要手段。通过监控,可以及时发现系统中的异常情况,例如事务状态回查失败、消息发送失败等。日志记录可以帮助开发者排查问题,分析系统性能。
资源隔离
在使用事务消息时,确保事务消息与其他普通消息的资源隔离,以避免相互影响。例如,可以为事务消息单独配置 Topic 和队列,确保事务消息的处理不受其他消息影响。
事务消息的重试机制
在某些情况下,事务消息的提交或回滚请求可能会失败。开发者需要考虑实现重试机制,以确保最终能够正确提交或回滚事务消息。重试机制可以通过定时任务或消息队列实现。
性能影响
事务消息的处理涉及多次网络通信和状态检查,可能会对系统性能产生一定影响。在高并发场景中,需要评估事务消息对系统性能的影响,并进行相应的优化。例如,可以通过批量处理、异步处理等方式提高性能。
RocketMQ事务消息(Transactional Message)
RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。RocketMQ的事务消息提供类似 X/Open XA 的分布式事务功能,通过事务消息能达到分布式事务的最终一致。
RocketMQ 事务消息的基本流程
RocketMQ 的事务消息是指在消息发送方发送消息后,需要经过两阶段提交来确保消息的可靠性传递和处理。
- Producer 发送 half 消息;
- Broker 先把消息写入 topic 是 RMQ_SYS_TRANS_HALF_TOPIC 的队列,之后给 Producer 返回成功;
- Producer 执行本地事务,成功后给 Broker 发送 commit 命令(本地事务执行失败则发送 rollback);
- Broker 收到 commit 请求后把消息状态更改为成功并把消息推到真正的 topic;
- Consumer 拉取消息进行消费。
代码如下:
public class ProducerTransactionListenerImpl implements TransactionListener {@Overridepublic LocalTransactionState executeLocalTransaction(Message msg, Object arg) {/*** 这里执行本地事务,执行成功返回LocalTransactionState.COMMIT_MESSAGE,执行失败返回* LocalTransactionState.ROLLBACK_MESSAGE,如果返回LocalTransactionState.UNKNOW,* Broker会回来查询,所以需要记录事务执行状态*/return LocalTransactionState.COMMIT_MESSAGE;}@Overridepublic LocalTransactionState checkLocalTransaction(MessageExt msg) {/*** 这里查询事务执行状态,根据事务状态返回LocalTransactionState.COMMIT_MESSAGE或* LocalTransactionState.ROLLBACK_MESSAGE,如果没有查询到返回LocalTransactionState.UNKNOW,* Broker会再次查询,可以记录查询次数,超过次数后返回ROLLBACK_MESSAGE*/return LocalTransactionState.UNKNOW;}
}
维度 8:消息索引
我们知道,RocketMQ 核心的数据文件有 3 个:CommitLog、ConsumeQueue 和 Index。其中Index 文件就是一个索引文件,结构如下图:
查找消息时,首先根据消息 key 的 hashcode 计算出 Hash 槽的位置,然后读取 Hash 槽的值计算 Index 条目的位置,从Index 条目位置读取到消息在 CommitLog 文件中的 offset,从而查找到消息。
在 Producer 发送消息时,可以指定一个 key,代码如下:
Message sendMessage = new Message("topic1", "tag1", message.getBytes());
sendMessage.setKeys("weiyiid");
这样可以通过 RocketMQ 提供的命令或者管理控制台来查询消息是否发送成功。
RocketMQ 的事务消息流程大致可以分为以下几个阶段:
-
发送
half
消息:生产者首先发送一条 "half
消息" 到 RocketMQ Broker。half
消息是指消息已经发送到 Broker,但此时消息状态不确定,该消息对消费者不可见。 -
执行本地事务:生产者在发送
half
消息之后,立即执行本地事务操作。例如,更新数据库、调用外部服务等。 -
提交或回滚事务消息:本地事务操作完成后,生产者根据本地事务的执行结果,向 Broker 发送 "提交" 或 "回滚" 请求。如果本地事务执行成功,则发送 "提交" 请求,使得
half
消息变为可消费的正式消息;如果本地事务失败,则发送 "回滚" 请求,Broker 将删除该half
消息。 -
事务状态回查:如果在规定时间内 Broker 没有收到提交或回滚请求,Broker 会主动向消息发送方发起事务状态回查,以确认该消息的最终状态。
Apache RocketMQ在4.3.0版中已经支持分布式事务消息,采用了2PC(两阶段提交)+ 补偿机制(事务状态回查)的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息,如上图所示。
RocketMQ 事务消息的源码分析
下面给出一个完整事务消息发送示例:
public class TransactionProducer {public static void main(String[] args) throws Exception {// 创建事务消息生产者TransactionMQProducer producer = new TransactionMQProducer("TransactionProducerGroup");producer.setNamesrvAddr("localhost:9876");// 设置事务状态回查监听器producer.setTransactionCheckListener(new TransactionCheckListener() {@Overridepublic LocalTransactionState checkLocalTransactionState(MessageExt msg) {// 处理事务状态回查逻辑System.out.println("Checking transaction state for message: " + new String(msg.getBody()));return LocalTransactionState.COMMIT_MESSAGE;}});// 启动生产者producer.start();// 发送事务消息Message msg = new Message("TransactionTopic", "TagA", "Transaction Message".getBytes());SendResult sendResult = producer.sendMessageInTransaction(msg, new LocalTransactionExecuter() {@Overridepublic LocalTransactionState executeLocalTransactionBranch(Message msg, Object arg) {// 执行本地事务逻辑System.out.println("Executing local transaction for message: " + new String(msg.getBody()));// 假设本地事务执行成功,返回 COMMIT_MESSAGE// 如果本地事务失败,返回 ROLLBACK_MESSAGEreturn LocalTransactionState.COMMIT_MESSAGE;}}, null);System.out.println("Send result: " + sendResult);// 阻塞主线程,防止退出System.in.read();// 关闭生产者producer.shutdown();}
}
客户端的事务消息处理
发送half
消息
发送half
消息的核心代码在 TransactionMQProducer 类中,通过 sendMessageInTransaction 方法实现:
public TransactionSendResult sendMessageInTransaction(Message msg, LocalTransactionExecuter tranExecuter, Object arg) {// 1. 发送`half`消息SendResult sendResult = this.defaultMQProducerImpl.send(msg);// 2. 执行本地事务LocalTransactionState localTransactionState = tranExecuter.executeLocalTransactionBranch(msg, arg);// 3. 根据本地事务状态提交或回滚消息this.endTransaction(msg, localTransactionState);return new TransactionSendResult(sendResult, localTransactionState);
}
在 sendMessageInTransaction 方法中,首先调用 send 方法发送half
消息,然后执行本地事务,并根据本地事务的结果调用 endTransaction 方法提交或回滚消息。
执行本地事务
本地事务的执行由 LocalTransactionExecuter 接口的实现类来完成。在实际使用中,用户需要实现该接口,并在 executeLocalTransactionBranch 方法中定义具体的本地事务逻辑。
public interface LocalTransactionExecuter {LocalTransactionState executeLocalTransactionBranch(final Message msg, final Object arg);
}
提交或回滚事务消息
提交或回滚事务消息的实现也在 TransactionMQProducer 类中,通过 endTransaction 方法完成:
private void endTransaction(Message msg, LocalTransactionState localTransactionState) {// 构建事务结束请求EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader();requestHeader.setCommitOrRollback(localTransactionState == LocalTransactionState.COMMIT_MESSAGE ? 0 : 1);requestHeader.setTranStateTableOffset(msg.getQueueOffset());requestHeader.setCommitLogOffset(msg.getCommitLogOffset());// 发送事务结束请求到 Brokerthis.defaultMQProducerImpl.endTransaction(msg, requestHeader);
}
在 endTransaction 方法中,根据本地事务的执行结果构建事务结束请求,并调用 endTransaction 方法将请求发送到 Broker。
事务状态回查
事务状态回查是由 Broker 发起的。当 Broker 在规定时间内没有收到提交或回滚请求时,会主动向消息发送方发起事务状态回查。回查的实现主要在 TransactionCheckListener 接口中:
public interface TransactionCheckListener {LocalTransactionState checkLocalTransactionState(final MessageExt msg);
}
消息发送方需要实现 TransactionCheckListener 接口,并在 checkLocalTransactionState 方法中定义如何检查本地事务的状态。
Broker 端的事务消息处理
Broker 端的事务消息处理主要在 TransactionalMessageServiceImpl 类中实现。Broker 负责接收half
消息、提交或回滚请求,并在必要时发起事务状态回查。
接收half
消息
Broker 接收half
消息的逻辑在 TransactionalMessageServiceImpl 类的 prepareMessage 方法中:
public PutMessageResult prepareMessage(MessageExtBrokerInner msgInner) {// 存储`half`消息return this.store.putMessage(msgInner);
}
提交或回滚消息
Broker 处理提交或回滚请求的逻辑在 TransactionalMessageServiceImpl 类的 commitMessage 和 rollbackMessage 方法中:
public boolean commitMessage(MessageExt msgExt) {// 提交消息return this.store.commitTransaction(msgExt);
}public boolean rollbackMessage(MessageExt msgExt) {// 回滚消息return this.store.rollbackTransaction(msgExt);
}
事务状态回查
Broker 发起事务状态回查的逻辑在 TransactionalMessageServiceImpl 类的 check 方法中:
public void check(long transactionTimeout, int transactionCheckMax, String topic) {// 遍历`half`消息队列,发起事务状态回查List<MessageExt> halfMessages = this.store.getHalfMessages(topic);for (MessageExt msg : halfMessages) {// 发起回查请求this.brokerController.getBroker2Client().checkProducerTransactionState(msg);}
}
RocketMQ分布式事务原理
分布式事务应用场景
随着应用的拆分,从单体架构变成分布式架构,那么每个服务或者模块也会有自己的数据库。一个业务流程的完成需要经过多次的接口调用或者多条MQ消息的发送。
那基于上面的应用场景,应该如何设计发送消息的流程,才能让这两个操作要么都成功,要么都失败呢?其实,可以参照XA两阶段提交的思想,把发送消息分成两步,然后把操作本地数据库也包括在这个流程中。
那么,在介绍原理之前,先科普一下两个新的概念:
1、半消息(Half Message):也就是暂不能投递消费者的消息。发送方已经将消息成功发送到了 MQ
服务端,但是服务端未收到生产者对这条消息的二次确认,这个时候,这条消息会被标记为“暂不能投递”状态。
2、消息回查(Message Status Check):由于网络闪断、生产者应用重启等原因,导致某条事务消息的
二次确认丢失,MQ 服务端通过扫描发现某条消息长期处于“半消息”时,需要主动向消息生产者询问该消息的最终状态,要么是Commit,要么Rollback。
如图所示,一共分为七个步骤
第一步:生产者向 MQ 服务端发送消息。
第二步:MQ 服务端将消息持久化成功之后,向发送方 ACK 确认消息已经发送成功,此时消息为半消息。
第三步:发送方开始执行本地数据库事务逻辑。
第四步:发送方根据本地数据库事务执行结果向 MQ Server 提交二次确认,MQ Server 收到 Commit状态则将半消息标记为可投递,订阅方最终将收到该消息;MQ Server 收到 Rollback 状态则删除半消息,订阅方将不会接受该消息。
第五步:在断网或者是应用重启的特殊情况下,按步骤4提交的二次确认最终未到达 MQ Server,经过固定时间后 MQ Server 将对该消息发起消息回查。
第六步:发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
第七步:发送方根据检查得到的本地事务的最终状态再次提交二次确认,MQ Server 仍按照步骤4对半消息进行操作(Commit/Rollback)。
RocketMQ事务消息使用限制
使用事务消息,有一些限制条件:
- 事务消息不支持延时消息和批量消息;
- 事务性消息可能不止一次被检查或消费,所以消费者端需要做好消费幂等;
为了避免单个消息被检查太多次而导致半队列消息累积,我们默认将单个消息的检查次数限制为 15 次(即默认只会回查15次),
我们可以通过 Broker 配置文件的 transactionCheckMax参数来修改此限制。
如果已经检查某条消息超过 N 次的话( N = transactionCheckMax ), 则 Broker 将丢弃此消息,并在默认情况下同时打印错误日志。
用户可以通过重写AbstractTransactionCheckListener 类来修改这个行为;
事务消息将在 Broker 配置文件中的参数 transactionMsgTimeout 这样的特定时间长度之后被检查。
当发送事务消息时,用户还可以通过设置用户属性 CHECK_IMMUNITY_TIME_IN_SECONDS 来改变这个限制,该参数优先于 transactionMsgTimeout 参数;
提交给用户的目标主题消息可能会失败,目前这依日志的记录而定。
它的高可用性通过 RocketMQ 本身的高可用性机制来保证,如果希望确保事务消息不丢失、并且事务完整性得到保证,建议使用同步的双重写入机制。
- 事务消息的生产者 ID 不能与其他类型消息的生产者 ID 共享。与其他类型的消息不同,事务消息允许反向查询、MQ服务器能通过它们的生产者 ID 查询到消费者。
- 1.事务消息执行时间限制:RocketMQ 要求事务消息的本地事务执行器(TransactionListener)在规定的时间内完成并返回事务执行结果,否则可能会触发回查机制。
- 2.回查机制的限制:如果发送方应用程序长时间未返回事务执行结果,RocketMQ 服务端会触发回查机制,这可能会增加系统的负担和网络开销。
- 3.不支持跨集群事务消息:RocketMQ 不支持跨集群的事务消息,即发送方和消费方需要处于同一个 RocketMQ 集群中。
- 4.事务消息的可靠性和性能权衡:由于事务消息需要经过两阶段提交,相比普通消息可能存在一定的性能损耗。
- 5.需要依赖本地事务执行器:发送方应用程序需要自行实现和注册本地事务执行器,确保本地事务的正确执行和结果反馈。
总的来说,RocketMQ 事务消息在确保消息可靠传递的同时,也需要开发者按照一定的规范来设计和实现本地事务执行器,以及处理可能的回查请求,这些都是在使用 RocketMQ 事务消息时需要考虑和遵循的限制。
RocketMQ事务消息怎么实现
在 RocketMQ 中,实现事务消息可以通过使用事务生产者(Transaction Producer)来完成。下面是一个简单的示例代码,演示了如何在 RocketMQ 中实现事务消息:
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class TransactionProducer {public static void main(String[] args) throws Exception {TransactionMQProducer producer = new TransactionMQProducer("transaction_producer_group");producer.setNamesrvAddr("your_namesrv_address");// 定义事务监听器TransactionListener transactionListener = new TransactionListenerImpl();producer.setTransactionListener(transactionListener);// 定义线程池来处理事务消息的预备、提交和回查ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2000), new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);thread.setName("client-transaction-msg-check-thread");return thread;}});producer.setExecutorService(executor);producer.start();// 发送事务消息Message message = new Message("YourTopic", "YourTag", "YourKeys", "YourMsg".getBytes());producer.sendMessageInTransaction(message, null);// 关闭生产者producer.shutdown();}
}class TransactionListenerImpl implements TransactionListener {@Overridepublic LocalTransactionState executeLocalTransaction(Message msg, Object arg) {// 在此处执行本地事务,根据执行结果返回不同的状态return LocalTransactionState.COMMIT_MESSAGE; // or ROLLBACK_MESSAGE or UNKNOW}@Overridepublic LocalTransactionState checkLocalTransaction(MessageExt msg) {// 在此处检查本地事务的状态,并返回相应的状态return LocalTransactionState.COMMIT_MESSAGE; // or ROLLBACK_MESSAGE or UNKNOW}
}
以上代码中,我们创建了一个事务生产者 TransactionMQProducer,并设置了事务监听器 TransactionListener。
在事务监听器的实现中,我们需要实现 executeLocalTransaction 方法来执行本地事务,以及 checkLocalTransaction 方法来检查本地事务的状态。
在 executeLocalTransaction 中,根据本地事务的执行结果返回不同的状态,而在 checkLocalTransaction 中,根据本地事务的状态返回相应的状态。
使用事务消息时,需要确保消息发送的可靠性,以及本地事务的正确执行和状态的正确返回。在实际场景中,还需要根据业务逻辑来合理处理事务消息的执行和状态回查。
相关文章:

科普文:微服务之Spring Cloud Alibaba消息队列组件RocketMQ工作原理
概叙 本文探讨 RocketMQ 的事务消息原理,并从源码角度进行分析,以及事务消息适合什么场景,使用事务消息需要注意哪些事项。 同时详细介绍RocketMQ 事务消息的基本流程,并通过源码分析揭示了其内部实现原理,尽管事务消…...

黑马头条vue2.0项目实战(五)——首页—频道编辑
目录 1. 使用页面弹出层 1.1 页面弹出层简单使用 1.2 创建频道编辑组件 1.3 页面布局 2. 展示我的频道 3. 展示推荐频道列表 3.1 获取所有频道 3.2 处理展示推荐频道 4. 添加频道 5. 编辑频道 5.1 处理编辑状态 5.2 切换频道 5.3 让激活频道高亮 5.4 删除频道 6.…...

Java:基础语法
基础语法 1. 基本结构类和方法 2. 变量和数据类型基本数据类型引用数据类型 3. 操作符算术操作符比较操作符逻辑操作符 4. 控制结构条件语句循环语句 5. 数组6. 方法7. 面向对象编程类和对象继承多态 8. 异常处理9. 常用类库 1. 基本结构 类和方法 Java程序的基本单位是类&am…...

安装bedtools详细步骤和详细介绍bedtools用法
安装bedtools详细步骤和详细介绍bedtools用法 一、安装bedtools详细步骤下载解压安装编译依赖编译设置环境变量激活环境变量执行命令查看版本二、详细介绍bedtools用法使用bedtools示例用法bedtools intersectbedtools bamtobedbedtools window一、安装bedtools详细步骤 下载 …...

21 - grace数据处理 - 补充 - 泄露误差改正 - Slepian局部谱分析法(一) - slepian分析法理论理解
21 - grace数据处理 - 泄露误差改正 - Slepian局部谱分析法 - slepian分析法理论理解 0 引言1 slepian谱分析法1.1 slepian谱分析法AI解释1.2 基于slepian谱分析法的GRACE数据处理应用2 slepian谱分析法关键过程实现2.1 求解正定特征方程2.2 计算slepian基函数2.3 计算Shannon数…...

WLAN国家码与信道顺从表
国家码和信道顺从表及信道功率限制 不同的国家和地区规定了在本国或本地区可以使用的信道、射频信号在信道中的最大发射功率。工作在不同信道的射频信号,信号强度可能会有差别。国家码和信道顺从表、各信道的功率限制值、信道编号和频率对照关系请参见国家码和信道…...

行为型设计模式1:状态/策略/命令
行为型设计模式:状态/策略/命令 (qq.com)...

【知识专栏丨python数分实战】天猫订单数据分析及可视化|taobao天猫订单接口
今天这篇文章将给大家介绍天猫订单数据分析及可视化案例。 import pandas as pdimport numpy as npfrom pyecharts.charts import Pie,Bar,Line,Map,Map3D,Funnelfrom pyecharts import options as optsimport matplotlib.pyplot as pltimport warningsimport seaborn as snsfr…...

[kimi笔记]为什么csc.exe不可以双击运行
csc.exe 是 C# 编译器的可执行文件,它是 .NET Framework 的一部分,用于编译 C# 源代码文件( .cs 文件)生成可执行文件( .exe 文件)或其他类型的程序集。 csc.exe 不能通过双击运行的原因有以下几点&…...

护眼大路灯哪个牌子好?2024学生护眼大路灯推荐
护眼大路灯哪个牌子好?护眼大路灯不仅能够提供日常的光线照明,还模拟了太阳光光线,使在室内用眼学习也能够有着自然光般的舒适感,但现在市场上有许多对产品质量把控不过关、光线效果欠佳、存有安全隐患的劣质护眼大路灯产品&#…...

Vue项目中手搓滑动校验模块-demo
实现代码 SliderCheck.vue <template><div class"drag" ref"dragDiv"><div class"drag_bg" ref"dragBg"></div><div class"drag_text" ref"dragText">{{ confirmWords }}</di…...

Socket如何实现客户端和服务器间的通信
Socket 是实现网络通信的一种机制,它允许在不同主机之间的进程通过网络进行数据交换。下面我将简要介绍如何使用 Socket 实现客户端和服务器间的通信。 客户端-服务器通信步骤: 服务器端: 创建服务器端 Socket: 服务器端通过创…...

基于Spring boot + Vue的校园论坛
作者的B站地址:程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址:程序员云翼-CSDN博客 1.项目技术栈: 前后端分离的项目 后端:Springboot MybatisPlus 前端:Vue ElementUI 数据库: …...

RabbitMQ高级特性 - 生产者消息确认机制
文章目录 生产者消息确认机制概述confirm 代码实现return 代码实现 生产者消息确认机制 概述 为了保证信息 从生产者 发送到 队列,因此引入了生产者的消息确认机制. RabbitMQ 提供了两种解决方案: 通过事务机制实现.通过发送确认机制(confi…...

webpack的loader机制
webpack的loader机制 loader本质上就是导出函数的JavaScript模块。导出的函数,可以用来实现内容的转换。 /* * param{string|Buffer} content 源文件的内容 * param{object} [map] SourceMap数据 * param{any} [meta] meta数据,可以是任何数据 * */ fu…...

(STM32笔记)十一、通过EXTI外部中断实现 按键控制LED
我用的是正点的STM32F103来进行学习,板子和教程是野火的指南者。 之后的这个系列笔记开头未标明的话,用的也是这个板子和教程。 十一、通过EXTI外部中断实现 按键控制LED 十一、通过EXTI外部中断实现 按键控制LED1、按键模块按键原理图按键程序思路 2、中…...

假如家里太大了,wifi连不上了怎么办
最近有个土豪朋友抱怨,他家里太大了,一个路由器的Wi-Fi信号根本无法覆盖他们家的每个房间,都没办法上网看奥运会比赛了。(还好我是穷人,就没有这种烦恼T_T)。 然后我问他为何不用一个路由器作主路由器&…...

elementPlus 设置el-input文本域固定高度和禁止下拉
elementPlus 设置el-input文本域固定高度和禁止下拉 话不多说直接上代码 // resize"none" 禁止下拉<el-inputv-model"textarea"style"width: 240px"type"textarea"resize"none"placeholder"请输入"/>// 设…...

(转)领导人必过的三道关
为什么企业领导人享受优厚的待遇,为什么董事会对企业领导人千挑万选?因为企业生命如此脆弱,据美国《财 富》杂志报道,世界500强企业平均寿命40年,世界1000强企业平均寿命30年,一般跨国公司平均寿命10年。而就是这脆弱…...

速盾:cdn可以定时刷新缓存吗?
CDN(Content Delivery Network)是一种通过在全球各地分布的服务器上缓存和传送网站内容的技术,以提高用户访问速度和降低服务器负载。CDN的缓存机制可以减少用户对源服务器的请求次数,从而提高网站的响应速度和性能。但是…...

代码随想录算法训练营第二十九天| 62.不同路径、63. 不同路径 II
写代码的第二十九天 继续动归!!! 62.不同路径 思路 解决问题1:dp[i][j]的的含义是什么?本题给的是一个二维的表,判断从左上角走到右下角有多少种路径,所以dp应该是二维数组,dp[i]…...

Go+Redis零基础到用户管理系统API实战_20240730 课程笔记
概述 如果您没有Golang的基础,应该学习如下前置课程。 Golang零基础入门Golang面向对象编程Go Web 基础Go语言开发REST API接口_20240728Go语言操作MySQL开发用户管理系统API教程_20240729Redis零基础快速入门_20231227 基础不好的同学每节课的代码最好配合视频进…...

ScreenAgent:基于LVLM的计算机控制智能体
ScreenAgent : A Vision Language Model-driven Computer Control Agent 论文链接: https://arxiv.org/abs/2402.07945https://arxiv.org/abs/2402.07945IJCAI 2024 1.概述 大型语言模型(LLM),诸如ChatGPT与GPT-4,在自然语言处理领域(涵盖生成、理解及对话等任务)展现出…...

谷粒商城实战笔记-129-商城业务-商品上架-nested数据类型场景
文章目录 扁平化处理扁平化处理导致的检索问题 解决方案:使用 nested 结构 在es的数据类型中有一个nested类型,本讲将重点讨论这个类型。 扁平化处理 PUT my_index/doc/1 {"group" : "fans","user" : [{"first&quo…...

axios请求响应拦截器
目录 axios-拦截器 拦截器的作用 请求拦截器-基本写法: axios请求拦截器-统一设置token 需求: 核心步骤: 关键代码: 响应拦截器-基本写法: axios响应拦截器-统一处理token失效 需求: 核心步骤: 关键代码: axios响应拦截器-数据剥离 需求: 核心步骤: 关键代码: ax…...

Python 中单例模式实现的几种方式
在设计模式中,单例模式是经常被提及和使用的一种模式。它保证一个类只有一个实例,并提供全局访问点。在Python中,有多种实现单例模式的方法。那么,如何选择合适的方法来实现单例模式呢? 单例模式在Python中的几种实现方…...

mysql数据库触发器同步数据
首先检查数据源库是否支持触发器,show ENGINES,如果FEDERATED是NO,表示未开启,如需开启,再mysql配置文件中,添加federated配置到mysqld下面。 一、同服务器不同库触发器同步,这里只举例插入数据…...

Prometheus-v2.45.0+Grafana+邮件告警
目录 普罗米修斯监控架构介绍 Prometheus 监控架构 1. 数据抓取(Scraping) 2. 时序数据库(TSDB) 3. 数据模型 4. PromQL 查询语言 5. 告警(Alerting) 6. Alertmanager 7. 可视化(Visu…...

LeetCode——572. 另一颗树的子树
通过万岁!!! 题目:给你两棵树,然后问subRoot是不是root的子树。也就是root某个节点的所有孩子节点在值和结构上完全与subRoot相同。思路:我的思路比较简单,就是遍历root,遇到root中…...

Spring Boot整合MyBatis-Flex
说明:MyBatis-Flex(官网地址:https://mybatis-flex.com/),是一款数据访问层框架,可实现项目中对数据库的访问,类比MyBatis-Plus。本文介绍,在Spring Boot项目整合MyBatis-Flex。 创…...