分布式事务 | 使用DTM 的Saga 模式 (一)


风晓
风晓 2023-12-31 09:26:22 51477 赞同 0 反对 0
分类: 资源
MassTransit、dotnetcore/CAP都提供了分布式事务的处理能力,但也仅局限于Saga和本地消息表模式的实现。那有没有一个独立的分布式事务解决方案,涵盖多种分布式事务处理模式,如Saga、TCC、XA模式等。有,目前业界主要有两种开源方案,其一是阿里开源的Seata,另一个就是DTM。其中Seata仅支持Java、Go和Python语言,因此不在.NET 的选择范围。DTM则通过提供简单易用的HTTP和gRPC接口,屏蔽了语言的无关性,因此支持任何开发语言接入,目前提供了Go、Python、NodeJs、Ruby、Java和C#等语言的SDK。 DTM,全称Distributed Transaction Manager,是一个分布式事务管理器,解决跨数据库、跨服务、跨语言更新数据的一致性问题。它提供了Saga、TCC、 XA和二阶段消息模式以满足不同应用场景的需求,同时其首创的子事务屏障技术可以有效解决幂等、悬挂和空补偿等异常问题。

DTM 事务处理过程及架构

那DTM是如何处理分布式事务的呢?以一个经典的跨行转账业务为例来看下事务处理过程。对于跨行转账业务而言,很显然是跨库跨服务的应用场景,不能简单通过本地事务解决,可以使用Saga模式,以下是基于DTM提供的Saga事务模式成功转账的的时序图:

从以上时序图可以看出,DTM整个全局事务分为如下几步:

  1. 用户定义好全局事务所有的事务分支(全局事务的组成部分称为事务分支),然后提交给DTM,DTM持久化全局事务信息后,立即返回
  2. DTM取出第一个事务分支,这里是TransOut,调用该服务并成功返回
  3. DTM取出第二个事务分支,这里是TransIn,调用该服务并成功返回
  4. DTM已完成所有的事务分支,将全局事务的状态修改为已完成

基于以上这个时序图的基础上,再来看下DTM的架构:

整个DTM架构中,一共有三个角色,分别承担了不同的职责:

  • RM-资源管理器:RM是一个应用服务,通常连接到独立的数据库,负责处理全局事务中的本地事务,执行相关数据的修改、提交、回滚、补偿等操作。例如在前面的这个Saga事务时序图中,步骤2、3中被调用的TransIn和TransOut方法所在的服务都是RM。
  • AP-应用程序:AP是一个应用服务,负责全局事务的编排,他会注册全局事务,注册子事务,调用RM接口。例如在前面的这个SAGA事务中,发起步骤1的是AP,它编排了一个包含TransOut、TransIn的全局事务,然后提交给TM
  • TM-事务管理器:TM就是DTM服务,负责全局事务的管理,作为一个独立的服务而存在。每个全局事务都注册到TM,每个事务分支也注册到TM。TM会协调所有的RM来执行不同的事务分支,并根据执行结果决定是否提交或回滚事务。例如在前面的Saga事务时序图中,TM在步骤2、3中调用了各个RM,在步骤4中,完成这个全局事务。

总体而言,AP-应用程序充当全局事务编排器的角色通过DTM提供的开箱即用的SDK进行全局事务和子事务的注册。TM-事务管理器接收到注册的全局事务和子事务后,负责调用RM-资源管理器来执行对应的事务分支,TM-事务管理器根据事务分支的执行结果决定是否提及或回滚事务。

快速上手

百闻不如一见,接下来就来实际上手体验下如何基于DTM来实际应用Saga进行分布式跨行转账事务的处理。

创建示例项目

接下来就来创建一个示例项目:

  1. 使用dotnet new webapi -n DtmDemo.Webapi创建示例项目。
  2. 添加Nuget包:Dtmcli 和Pomelo.EntityFrameworkCore.MySql
  3. 添加DTM配置项:
 
 
{
 
"dtm": {
 
"DtmUrl": "http://localhost:36789",
 
"DtmTimeout": 10000,
 
"BranchTimeout": 10000,
 
"DBType": "mysql",
 
"BarrierTableName": "dtm_barrier.barrier",
 
}
 
}
 
  1. 定义银行账户BankAccount实体类:
 
 
namespace DtmDemo.WebApi.Models
 
{
 
public class BankAccount
 
{
 
public int Id { get; set; }
 
public decimal Balance { get; set; }
 
}
 
}
 
  1. 定义DtmDemoWebApiContext数据库上下文:
 
 
using Microsoft.EntityFrameworkCore;
 
 
 
namespace DtmDemo.WebApi.Data
 
{
 
public class DtmDemoWebApiContext : DbContext
 
{
 
public DtmDemoWebApiContext (DbContextOptions<DtmDemoWebApiContext> options)
 
: base(options)
 
{
 
}
 
 
 
public DbSet<DtmDemo.WebApi.Models.BankAccount> BankAccount { get; set; } = default!;
 
}
 
}
 
  1. 注册DbContext 和DTM服务:
 
 
using Microsoft.EntityFrameworkCore;
 
using DtmDemo.WebApi.Data;
 
using Dtmcli;
 
 
 
var builder = WebApplication.CreateBuilder(args);
 
var connectionStr = builder.Configuration.GetConnectionString("DtmDemoWebApiContext");
 
// 注册DbContext
 
builder.Services.AddDbContext<DtmDemoWebApiContext>(options =>
 
{
 
options.UseMySql(connectionStr, ServerVersion.AutoDetect(connectionStr));
 
});
 
 
 
// 注册DTM
 
builder.Services.AddDtmcli(builder.Configuration, "dtm");
 
  1. 执行dotnet ef migrations add 'Initial' 创建迁移。
  2. 为便于初始化演示数据,定义BankAccountController如下,其中PostBankAccount接口添加了await _context.Database.MigrateAsync();用于自动应用迁移。
 
 
using Microsoft.AspNetCore.Mvc;
 
using Microsoft.EntityFrameworkCore;
 
using DtmDemo.WebApi.Data;
 
using DtmDemo.WebApi.Models;
 
using Dtmcli;
 
 
 
namespace DtmDemo.WebApi.Controllers
 
{
 
[Route("api/[controller]")]
 
[ApiController]
 
public class BankAccountsController : ControllerBase
 
{
 
private readonly DtmDemoWebApiContext _context;
 
 
 
public BankAccountsController(DtmDemoWebApiContext context)
 
{
 
_context = context;
 
}
 
[HttpGet]
 
public async Task<ActionResult<IEnumerable<BankAccount>>> GetBankAccount()
 
{
 
return await _context.BankAccount.ToListAsync();
 
}
 
 
 
[HttpPost]
 
public async Task<ActionResult<BankAccount>> PostBankAccount(BankAccount bankAccount)
 
{
 
await _context.Database.MigrateAsync();
 
_context.BankAccount.Add(bankAccount);
 
await _context.SaveChangesAsync();
 
 
 
return Ok(bankAccount);
 
}
 
}
 

应用Saga模式

接下来定义SagaDemoController来使用DTM的Saga模式来模拟跨行转账分布式事务:

 
 
using Microsoft.AspNetCore.Mvc;
 
using Microsoft.EntityFrameworkCore;
 
using DtmDemo.WebApi.Data;
 
using DtmDemo.WebApi.Models;
 
using Dtmcli;
 
using DtmCommon;
 
 
 
namespace DtmDemo.WebApi.Controllers
 
{
 
[Route("api/[controller]")]
 
[ApiController]
 
public class SagaDemoController : ControllerBase
 
{
 
private readonly DtmDemoWebApiContext _context;
 
private readonly IConfiguration _configuration;
 
private readonly IDtmClient _dtmClient;
 
private readonly IDtmTransFactory _transFactory;
 
 
 
private readonly IBranchBarrierFactory _barrierFactory;
 
private readonly ILogger<BankAccountsController> _logger;
 
 
 
public SagaDemoController(DtmDemoWebApiContext context, IConfiguration configuration, IDtmClient dtmClient, IDtmTransFactory transFactory, ILogger<BankAccountsController> logger, IBranchBarrierFactory barrierFactory)
 
{
 
this._context = context;
 
this._configuration = configuration;
 
this._dtmClient = dtmClient;
 
this._transFactory = transFactory;
 
this._logger = logger;
 
this._barrierFactory = barrierFactory;
 
}
 
}
 

对于跨行转账业务,使用DTM的Saga模式,首先要进行事务拆分,可以拆分为以下4个子事务,并分别实现:

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  125
统信桌面专业版【全盘安装UOS系统】介绍  120
银河麒麟桌面操作系统安装佳能打印机驱动方法  111
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!