Netcore CAP分布式事务实践

发布时间 2023-08-29 14:26:00作者: 想睡觉的小坤

Netcore CAP分布式事务实践

1、 分布式事务解决方案之可靠消息最终一致性

可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。

 

事务发起方(消息生产方)将消息发给消息中间件,事务参与方从消息中间件接收消息,事务发起方和消息中间件之间,事务参与方(消息消费方)和消息中间件之间都是通过网络通信,由于网络通信的不确定性会导致分布式事务问题。

 

事务的ACID特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

分布式事务CAP理论:自行百度

2、 可靠消息最终一致性方案要解决以下几个问题

A. 本地事务与消息发送的原子性问题

本地事务与消息发送的原子性问题即:事务发起方在本地事务执行成功后消息必须发出去,否则就丢弃消息。即实现本地事务和消息发送的原子性,要么都成功,要么都失败。本地事务与消息发送的原子性问题是实现可靠消息最终一致性方案的关键问题。

场景1,先发送消息,再操作数据库:

              begin transaction;

             //1.发送MQ

             //2.数据库操作

commit transation;

结论:无法保证数据库操作与发送消息的一致性,因为可能发送消息成功,数据库操作失败

 

场景2,先进行数据库操作,再发送消息:

              begin transaction;

             //1.数据库操作

             //2.发送MQ

commit transation;

结论:如果发送MQ消息失败,就会抛出异常,导致数据库事务回滚。但如果是超时异常(commit),数据库回滚,但MQ其实已经正常发送了,同样会导致不一致

B. 事务参与方接收消息的可靠性

事务参与方必须能够从消息队列接收到消息,如果接收消息失败可以重复接收消息

C. 消息重复消费的问题

由于网络2的存在,若某一个消费节点超时但是消费成功,此时消息中间件会重复投递此消息,就导致了消息的重复消费。

要解决消息重复消费的问题就要实现事务参与方的方法幂等性。

D. 12

3、 解决方案-本地消息表方案

本地消息表这个方案最初是eBay提出的,此方案的核心是通过本地事务保证数据业务操作和消息的一致性,然后通过定时任务将消息发送至消息中间件,待确认消息发送给消费方成功再将消息删除。

 

思路:用户表和消息表通过本地事务保证一致

begin transaction;

         //1.新增用户

         //2.存储积分消息日志

commit transation;

这种情况下,本地数据库操作与存储积分消息日志处于同一个事务中,本地数据库操作与记录消息日志操作具备原子性。

 

定时任务扫描日志

启动独立的线程,定时对消息日志表中的消息进行扫描并发送至消息中间件,在消息中间件反馈发送成功后删除该消息日志,否则等待定时任务下一周期重试。

 

消费消息

使用MQ的ack(即消息确认)机制,消费者监听MQ,如果消费者接收到消息并且业务处理完成后向MQ发送ack(即消息确认),此时说明消费者正常消费消息完成,MQ将不再向消费者推送消息,否则消费者会不断重试向消费者来发送消息。

  积分服务接收到”增加积分“消息,开始增加积分,积分增加成功后向消息中间件回应ack,否则消息中间件将重复投递此消息。

4、 CAP介绍

CAP 是一个EventBus,同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架。它有助于创建可扩展,可靠并且易于更改的微服务系统。

文档:https://cap.dotnetcore.xyz/user-guide/zh/getting-started/introduction/

5、 CAP架构

 

6、 CAP开始

安装CAP包

 

CAP支持的消息队列:

 

CAP支持的数据库:

 

文档:https://github.com/dotnetcore/CAP

7、 添加完引用后,在项目中添加CAP支持

 

 

运行程序,数据库CapDemo中,自动添加了两张表:

 

 

启用CAP仪表盘,访问地址:http://url:port/cap

我们这里是:https://localhost:5001/CAP

 

8、 Postman访问core的https地址

关闭SSL证书认证

 

 

9、 重试间隔:

在默认情况下,重试将在发送和消费消息失败的 4分钟后 开始,这是为了避免设置消息状态延迟导致可能出现的问题。

发送和消费消息的过程中失败会立即重试 3 次,在 3 次以后将进入重试轮询,此时 FailedRetryInterval 配置才会生效。

https://cap.dotnetcore.xyz/user-guide/zh/cap/configuration/

看Demo

10、           补偿事务(Compensating transaction)

某些情况下,消费者需要返回值以告诉发布者执行结果,以便于发布者实施一些动作,通常情况下这属于补偿范围。

你可以在消费者执行的代码中通过重新发布一个新消息来通知上游,CAP 提供了一种简单的方式来做到这一点。 你可以在发送的时候指定 callbackName 来得到消费者的执行结果,通常这仅适用于点对点的消费。以下是一个示例。

 

例如,在一个电商程序中,订单初始状态为 pending,当商品数量成功扣除时将状态标记为 succeeded ,否则为 failed。

看Demo

11、           借用一个图

 

12、           CAP的一些问题:

 

13、           12

14、           12