RabbitMQ——解决分布式事务问题,RabbitMQ的重要作用之一!!!通过可靠生产和可靠消费来完美解决!

了解什么是分布式事务问题

分布式事务是指涉及多个独立的计算机系统(也称为节点或参与者)之间的事务处理。在分布式系统中,每个节点可能各自拥有自己的数据存储和事务管理机制。分布式事务的目标是保证在跨多个节点执行的一系列操作可以以一致和可靠的方式执行和提交,即使在面对故障或并发操作时也能保持数据的完整性和一致性。

分布式事务通常包括以下四个关键属性:

  1. 原子性(Atomicity):要么所有的操作都成功执行并提交,要么所有的操作都回滚,保证所有节点的数据状态一致。
  2. 一致性(Consistency):事务执行前和执行后系统的状态保持一致。
  3. 隔离性(Isolation):事务在执行期间对其他事务是隔离的,即每个事务都感觉不到其他事务的存在。
  4. 持久性(Durability):一旦事务提交,其结果必须永久存储,即使在系统故障的情况下也能恢复。

实现分布式事务可以采用两阶段提交(Two-Phase Commit)协议或三阶段提交(Three-Phase Commit)协议等机制。这些协议通过协调参与者之间的状态和决策来实现分布式事务的一致性。然而,由于分布式事务需要跨越网络和多个节点进行通信和协调,因此可能会面临性能和可靠性等挑战。

举例说明:
当服务A通过restTemplate调用服务B的接口,服务A会持久化数据到A数据库,而服务B会持久化数据到数据库B,那么如果这个时候数据传输中间出现了问题,数据库A出现了持久化,而服务B持久化失败执行了回滚,但是数据库A是无法进行事务的回滚了,这个时候可能就会造成脏数据了

通过RabbitMQ来解决分布式事务问题

MQ解决分布式事务问题

可靠生产

主要是通过一张冗余表和定时任务解决了可靠生产的问题

在本地数据库中创建一张冗余表
(1)如果消息可以正常发送到MQ,并且MQ给与了确认消息,那么这条数据会在冗余表中设置status为1;
(2)如果MQ此时宕机,那么这条数据就会存储到冗余表中,设置状态码为0(默认状态),会创建一个定时任务,定时将冗余的消息再发送到MQ中;
(3)如果发送次数超过两会,也就是status字段为2,那么就会判断是消息出现了问题,然后通知人工来排查问题所在

可靠消费

1.首先创建一个消费者,监听队列中的消息


2.如果消费者在消费消息的时候,出现了异常(代码中默认设置的是1/0的异常),那么就会触发MQ的重试机制,会导致死循环。解决消息重试的几种方案:(面试常问)
(1)控制重发的次数
在配置文件中进行相关重试次数的配置,如果达到了最大的重试次数,会把这条消息在队列中移除!
如果我们在配置文件中没有开启手动ack,使用默认的自动ack,那么会存在消息丢失的情况,一般不会使用这种方法

(2)try + catch + 手动ack
①第一步首先要在yaml配置文件开启手动ack,这样消息在出现异常,甚至是超过重试次数的时候就不会被移除,我们还能将这条消息转移到死信队列中!

②在消费者消费消息的业务代码中,在catch中设置ack
调用basicNack方法,参数requeue,如果设置成false,那么消息如果消异常,就会将他转移到死信队列中,如果设置成true,那么就会将这条消息移除掉

(3)try + catch + 手动ack + 死信队列处理 + 人工干预
①在上面开启手动ack的基础上,创建死信交换机和死信队列,绑定到接收消息的队列中,如果消息出现异常,那么就会将消息转移到死信队列中

②创建一个新的消费者来监听死信队列,这个消费者中的业务逻辑就不能包含处理异常消息的代码了,一般到了监听死信队列的情况下,再往后就得需要人工干预了!

③还需要考虑数据的幂等性,就是要保证数据在数据库中不被重复添加
直接把订单号设置成主键,这样主键就一定是唯一的啦!
或者是使用分布式锁!

至此,关于RabbitMQ解决分布式事务的问题介绍完毕,后续还会持续更新相关技术点,敬请期待~~~

### Go语言中gRPC分布式事务解决方案的最佳实践 在Go语言环境中,利用gRPC解决分布式事务问题可以通过多种方式实现。以下是几种常见的最佳实践: #### 1. **两阶段提交 (2PC)** 两阶段提交是一种强一致性的分布式事务管理协议,在gRPC场景下可以借助其可靠性来确保数据的一致性[^2]。具体来说,服务端客户端之间通过gRPC通信完成准备阶段提交/回滚阶段的操作。 - 准备阶段:调用方发送请求到多个参与的服务节点,这些节点会锁定资源并返回确认状态。 - 提交或回滚阶段:如果所有参与者都成功,则发起正式提交;若有任意一方失败,则触发全局回滚操作。 虽然此方法能够提供较高的数据一致性保障,但由于其实现较为复杂且性能开销较大,因此并不适合高频并发业务场景。 #### 2. **TCC 补偿模式** TCC(Try-Confirm-Cancel)作为一种显式的事务控制模型,适用于那些对实时性准确性要求极高的应用环境[^3]。它要求开发者针对每一个业务逻辑分别定义尝试执行(Try)、确认提交(Confirm)以及取消操作(Cancel),从而形成闭环流程。 然而需要注意的是,由于该策略具有较强的侵入特性——即需要修改现有代码结构以支持上述三个动作的设计思路——所以通常只推荐应用于特定领域内的核心交易环节之中。 ```go type OrderService struct { // ... } func (s *OrderService) CreateOrder(ctx context.Context, req *pb.CreateOrderRequest) (*pb.CreateOrderResponse, error){ err := s.TryCreateOrder(req) if err != nil{ return nil,err } confirmErr:=s.ConfirmCreateOrder(req.OrderId) if confirmErr!=nil{ cancelErr:=s.CancelCreateOrder(req.OrderId) if cancelErr!=nil{ log.Fatalf("Both Confirm and Cancel failed:%v",confirmErr,cancelErr) }else{ log.Printf("Cancel succeeded after Confirm failure.") } } resp := &pb.CreateOrderResponse{OrderId:req.OrderId} return resp,nil } ``` #### 3. **基于可靠消息队列的最终一致性方案** 此类技术路线主要依赖于异步消息传递机制达成目标效果。例如Kafka,RabbitMQ等工具都可以作为中间件参与到整个过程中去。当生产者向消费者发出一条记录之后,即使暂时未能立即得到反馈结果也不会影响后续步骤继续推进下去直到达到预期目的为止[^4]。 在这种架构设计里边儿,我们往往还会引入额外的时间戳或者版本号字段用来辅助判断重复消费等情况的发生与否进而采取相应措施加以规避风险隐患的存在可能带来的负面影响。 #### 4. **Control Loop 结合 Etcd Watch 实现事件驱动型分布式事务协调器** 受启发自 Kubernetes 中控制器循环(Control-loop)理念的影响,有人提出了另一种新颖而高效的应对办法那就是运用 etcd watch 功能构建起一套专门用于处理跨平台间相互协作关系的任务调度框架-hptx 或者说是 dbpack 。前者专注于服务于单一编程语种下的项目需求; 后者则更加注重兼容不同种类的语言生态体系之间的无缝衔接互通有无的能力表现形式上来看待事物的发展变化规律特点等方面的内容探讨交流学习过程中的心得体会体会感悟分享给大家共同进步成长起来吧! --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Be explorer

若认可笔者文章,手头富裕望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值