.net core分布式事务落地(2)-最终一致性方案落地(DotNetCore.CAP)

使用DotNetCore.CAP解决分布式事务

目录: 

  1. 方案简介
  2. 方案流程图
  3. 环境搭建
    1. 环境依赖
    2. 环境配置
  4. 代码实现
    1. 数据库初始化
    2. 创建应用程序
    3. 运行应用程序
    4. 结果

1. 方案简介

       针对CAP事务,在本文中主要介绍.net core是如何实现最终一致性。整个方案,主要是基于 开源项目 DotNetCore.CAP +RabbitMQ+Mysql来实现的。

       首先介绍下DotNetCore.CAP ,该项目是.net core的一个用于实现分布式事务(最终一致性)的开源项目,其项目集成了:

  1. 队列:RabbitMQ、AmazonSQS、RedisStreams
  2. 数据库本地消息表支持:Mysql、SqlServer、PostgreSql、MongoDB。
  3. 同时还支持AzureServiceBus、NATS等云服务消息总线。

2. 方案流程图

3. 环境搭建

          3.1环境依赖:

                     1. docker,安装MySql8、RabbitMQ集群

                     2. 程序运行环境:.net 5

   3.2 环境配置

                     1. docker安装mysql8,如果电脑上已经有了mysql,那跳过这个步骤。

                            运行docker命令:docker run --name mysqlServer  --restart=always -p 6031:3306 -e MYSQL_ROOT_PASSWORD=pwd -d mysql --lower_case_table_names=1

      2. 安装RabbitMQ集群,本次项目将安装三个rabbitmq:

docker run -d --hostname rabbit1 --name myrabbit1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

docker run -d --hostname rabbit2 --name myrabbit2 -p 5673:5672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

docker run -d --hostname rabbit3 --name myrabbit3 -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management

      3. 设置RabbitMQ集群

#设置节点1:
docker exec -it myrabbit1 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl start_app exit
#设置节点2,加入到集群:
docker exec -it myrabbit2 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl join_cluster --ram rabbit@rabbit1 rabbitmqctl start_app exit
#设置节点3,加入到集群:
docker exec -it myrabbit3 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl join_cluster --ram rabbit@rabbit1 rabbitmqctl start_app exit

      4. 结果

图:环境配置成功示意图

4. 代码实现

   本次介绍主要是结合场景:一个用户支付订单,调用支付,并且更新订单数据。因订单和支付分别属于两个不同系统,所以基于这个场景来进行分布式事务的演示。

   示例代码已上传到码云:https://gitee.com/fengwuyan/distributed-transaction-demo

  4.1 数据库初始化

    打开doc文件夹下的数据库脚本文件夹,运行两个sql脚本,会创建两个数据库,分别是OrderService和PaymentService。

 

图:数据库初始化

  4.2 创建应用程序

  1. 第一步:

    使用vs分别创建OrderService和PaymentService的WebApi程序,以及创建一个EF.Model访问数据库类库程序。

图:程序目录结构

  2. 第二步:

    因本次演示节省时间,订单系统和支付系统都使用同一个ef项目。引用EFCore及EF mysql的支持包。创建order和payment表对应的实体类,及efcontext实现类

图:EF.Model

    3.第三步:

    在OrderService和PaymentService项目中引用以下包:

    • DotNetCore.CAP
    • DotNetCore.CAP.MySql
    • DotNetCore.CAP.RabbitMQ

    并且在StartUp中配置CAP及EF类:

图:WebApi的CAP及EF配置

  4.第四步:

         在PaymentService创建控制器:PaymentController,注入CAP发布消息对象,及EF访问类和其他对象等

图:注入支付控制器所需对象

  5.第五步:

    创建一个支付方法,在更新完支付信息之后,使用cap推送支付成功消息

图:支付方法

  6.第六步:

    在OrderService创建控制器:OrderController,注入CAP发布消息对象,及EF访问类和其他对象等

图:订单系统控制器对象注入

       7.第七步:

    创建一个消费消息的方法,用户处理本地消息表数据,完成订单更新,特性标签CapSubscribe 用于指示该方法处理消息队列的名称,该名称跟支付系统内发送消息的名称相同。

 

 

  4.3 运行程序

              1. 第一步

      在orderservice程序根目录运行cmd命令:dotnet run --urls http://*:2001,将orderservice成功运行起来

图:orderservice运行图

    2.第二步:

      在paymentservice程序根目录运行cmd命令:dotnet run --urls http://*:2002 ,将paymentservice成功运行起来

 

 

    3.第三步:

                     使用postman工具,发送post请求,http://127.0.0.1:2002/api/Payment/apply?paymentId=1 然后成功的发现,报错了,错误的大致意思是,你传入的参数不是MysqlParameter。

 

 

      最终,没办法,只能把源码下下来调试,最终发现CAP 默认MySql使用的是用的MysqlConnector,而EF默认用的是Mysql.Data包,这两个包都有MysqlParameter等对象,但是不是同一个,于是只能对源码进行修改,将MysqlConnector包替换成MySql.Data包。修改项目引用,CAP的包都引用本地的。

 

       然后重新启动项目,访问2002的apply接口。

  4.4 结果

    支付成功,也成功的更新了订单

图:程序运行结果图 

 

--------------------------------------------------------结束语---------------------------------------------------------------

  相信大家,经过整个了解,对与如何解决分布式事务,已经有了一定的了解,在此祝大家技术牛哄哄。

 

posted @ 2021-08-23 00:43  隔壁老黎  阅读(960)  评论(3)    收藏  举报