Asp.Net Core&CAP实现分布式事务
需要注意的是标题中的CAP不是指的CAP理论,而是园区大神杨晓东实现的框架,CAP框架基于本地消息表用最终一致性实现分布式事务。
本地消息表
首先我们考虑一个场景,在将用户信息更改后,需要发送一条消息到消息队列、缓存或是写入到其他库中。这个过程涉及到一个本地库与MQ、本地库与Cache或是本地库与其他库两者之间的事务问题,不能用简单的数据库事务控制了。
这种分布式事务下,常用的解决方案有2PC、3PC等强一致性保证的,也有TCC、Sagas模型、本地消息表、内嵌本地消息表的MQ等最终一致性保证的。
而在很多异步场景下,允许系统存在短暂的不一致,只需达到最终一致,比起强一致性那种刚性事务,采用柔性事务,在很多场景下更有利于我们去实现。
执行过程
在使用CAP框架前,先熟悉下作为分布式事务解决方案之一的本地消息表工作过程。
- 消息发起方(如图左侧部分)和消息接收方(如图右侧部分),先额外建一套消息表,用来记录及跟踪消息内容及状态。
- 当有请求到消息发起方时,处理完业务逻辑发布消息将业务数据和消息数据一同提交到本地表中,此时为本地事务。
- 本地事务没有问题后,将消息发送到MQ传递给消息消费方。如果消息发送失败,会进行重试发送。
- 消息消费方,接收并处理消息,完成自己的业务逻辑,此时为消息消费方本地事务,如果本地事务完成,则更改接收消息的状态,更改本地,如果处理失败,那么可再次重试执行。
- 最终,左侧事务与右侧事务达到最终一致。
CAP框架
CAP是一个在分布式系统中(SOA,MicroService)实现事件总线及最终一致性(分布式事务)的一个开源的 C# 库,具有轻量级,高性能,易使用等特点。
- 具有 Event Bus 的所有功能,提供了更加简化的方式来处理EventBus中的发布/订阅。
- 具有消息持久化的功能,当服务进行重启或者宕机时,可以保证消息的可靠性。
- 基于本地消息表实现了分布式事务中的最终一致性。
- 集成了可视化页面方便观察消息状态。
- 提供了一系列Nuget包以选择需要的工具接入。
- 第一个包DotNetCore.CAP为必须要安装的。
- 可以依据消息队列的不同选择用RabbitMQ、Kafka或是AzureServiceBus等。
- 根据服务使用的数据库情况选择需要将本地消息表落库,可以选择SqlServer、MySql、PostgreSql、MongoDB等,或是直接使用内存存储,方便快速实践。
场景案例
依照EShopOnContainers中的一张图来实现一个例子,用户更新用户信息,将更新的部分通过事件发送到消息队列中,下游的购物车和订单服务侦听到消息,更改买家信息。
在此基础上行,设计三个上下文,并分别集成CAP,借助RabbitMQ作为消息队列,对于UserService、BasketService和OrderService,都直接使用了数据库(当然可以不仅限于数据库)。
服务建立
项目创建
开始建立几个服务,新建空白解决方案,依次建立三个WebApi项目,并移除默认的控制器。
简单设计下,在三个服务中创建三个DbContext,对应三个独立的数据库。
- UserService中创建UserInfo实体及UserDbContext
- BasketService中创建Basket实体及BasketDbContext
- OrderService中创建Order实体及OrderDbContext
安装Nuget包
在三个服务中均安装完如下选中的包,此次Demo中为方便快速实践,选择RabbitMQ作为消息队列,MySql作为数据库存储。
对于EFCore及MySql包,安装了如下几个包
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Tools
Pomelo.EntityFrameworkCore.MySql
注意此处EFCore中MySql版本和CAP中MySql版本两者间依赖的MySqlConnector不一致会优点问题
配置服务
需要对CAP进行设置,比如使用的是什么数据库、什么消息队列及配置下消息队列参数,这一系列初始化设置在Startup.cs中配置好。
- ConfigureService中配置DbContext和CAP服务
- Configure中CAP的引入中间件
- 利用EFCore的迁移命令生成下数据库迁移脚本,将DbContext内实体生成到数据库中
- 单个服务启动后,CAP组件会将内置表创建到数据库中。
- 服务全部启动后,RabbitMQ Client会自动注册到RabbitMQ Server中同时创建好给定的Exchange(不给定则使用默认值),存在订阅的服务则注册队列绑定到给定的Exchange下。
发布事件
在 UserService中UserController 中注入ICapPublisher,使用Patch接口更新一个Address,然后使用ICapPublisher发布一条消息。
- 更新本地User表内信息。
- 借助_capPublisher发布事件,先将事件信息记录到本地MqPublish表。
- 前两步都是针对本地表操作,一个事务保证,写入MqPublish成功后再由CAP将记录发送到RabbitMQ中。
订阅事件
在BasketService和OrderService中完成事件的订阅。各自新建了一个Handler来处理消息。在Handler中对处理的方法加上CapSubscribe特性,其中监听的是发布事件时发送的事件名或消息名。
- BasketService收到RabbitMQ中的消息,CAP将消息写入到MqReceive中。
- 调用相应的Handler处理事件。
- 更新Basket本地表,本地事务完成被提交。
- CAP组件将本地的MqReceive相关记录更改状态到完成,如本地事务提交失败,则再次重试。
总结
抛弃强一致性想法借助最终一致性完成,将分布式事务拆分成多个本地事务进行处理。采用最终一致性来使得所有本地事务完成,即使部分出现失败,也可重试,如重试机制无效最终借助人力完成。
在异步场景下,CAP及其方便了我们去处理分布式事务的过程。
当前RabbitMQ场景下,当某个服务做多个部署时,同一个队列仍能保证一个消费者消费。这也避免了有些场景下,需要对资源加锁来防止同时消费场景。
参考
2021-04-28,望技术有成后能回来看见自己的脚步
Asp.Net Core&CAP实现分布式事务的更多相关文章
- 【转】.NET Core 事件总线,分布式事务解决方案:CAP
[转].NET Core 事件总线,分布式事务解决方案:CAP 背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用 ...
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...
- asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程
最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...
- .net core 下的分布式事务锁
原文:.net core 下的分布式事务锁 目录 系统分布式锁的用法 锁的实现 锁的使用 API内的范例: 引用链接 系统分布式锁的用法 公司框架新增功能分布式锁: 锁的性能之王: 缓存 > Z ...
- 【转】asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程
最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...
- ASP.NET Core中间件实现分布式 Session(转载)
ASP.NET Core中间件实现分布式 Session 1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件 ...
- .NET Core 事件总线,分布式事务解决方案:CAP
背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景 ...
- .NET Core 事件总线,分布式事务解决方案:CAP 基于Kafka
背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景 ...
- 【无私分享:ASP.NET CORE 项目实战(第十三章)】Asp.net Core 使用MyCat分布式数据库,实现读写分离
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 MyCat2.0版本很快就发布了,关于MyCat的动态和一些问题,大家可以加一下MyCat的官方QQ群:106088787.我 ...
随机推荐
- eclipse中lombok注解不生效
现象:eclipse中在对象上使用lombok的@Data,引用get方法时,没有set.get方法. 解决办法: 1.在lombok官网(https://www.projectlombok.org/ ...
- SpringBoot源码解析
1.@SpringBootApplication springboot采用注解方式开发的,当创建了一个springboot项目时,在启动类上会有一个注解@SpringBootApplication,这 ...
- Python爬虫系统化学习(3)
一般来说当我们爬取网页的整个源代码后,是需要对网页进行解析的. 正常的解析方法有三种 ①:正则匹配解析 ②:BeatuifulSoup解析 ③:lxml解析 正则匹配解析: 在之前的学习中,我们学习过 ...
- 保证软件开发过程遵循ISO 26262功能安全标准的十个主要进阶步骤
保证软件开发过程遵循ISO 26262功能安全标准的十个主要进阶步骤 为保障汽车软件质量,使软件开发符合ISO 26262功能安全标准,需要我们对开发流程做出改进,并与2018年的更新同步. 本视频课 ...
- Vue前端项目的搭建流程
1. 安装Vue和Nodejs 2. 创建项目 vue create eduonline-web
- 如何使用 Github Actions 自动抓取每日必应壁纸?
如何白嫖 Github 服务器自动抓取必应搜索的每日壁纸呢? 如果你访问过必应搜索网站,那么你一定会被搜索页面的壁纸吸引,必应搜索的壁纸每日不同,自动更换,十分精美.这篇文章会介绍如何一步步分析出必应 ...
- 记录core中GRPC长连接导致负载均衡不均衡问题 二,解决长连接问题
题外话: 1.这几天收到蔚来的面试邀请,但是自己没做准备,并且远程面试,还在上班时间,再加上老东家对我还不错.没想着换工作,导致在自己工位上做算法题不想被人看见,然后非常紧张.估计over了.不过没事 ...
- burpsuite 隐藏 detectportal.firefox.com
0x00原由 抓包时经常出现detectportal.firefox.com,不利于我们的渗透工作 0x01解决方法 在输入框输入:about:config 然后设置以下选项:network. ...
- WPF 基础 - 点击事件的执行顺序及 Button 点击事件的特殊性
1. 点击事件的执行顺序 PreviewMouseLeftButtonDown PreviewMouseDown MouseLeftButtonDown MouseDown PreviewMouseL ...
- Apache配置 5.访问日志不记录静态文件
介绍:项目中的CSS.图片.js都是静态文件.一般会将静态文件放到一个单独的目录中,以方便管理. 1. 配置 # vim /usr/local/apache2.4/conf/extra/httpd-v ...