前面对于分布式事务也讲了好几篇了,但是还没有实战过。那么本篇我们就来演示下如何在 .NET 环境下实现一个基于可靠消息的分布式事务。基于可靠消息的分布式事务流程上还是比较清晰明了的,但是要用代码去一个个实现还是比较费事的。通过分析可以发现这个事务的关键点就是要在真正的业务逻辑的前面、后面插入对应的流程。很明显这种流程是可以通过 AOP 技术来简化操作的。于是就有了 AgileDT 。AgileDT 使用 Natasha 在启动的时候动态生成代理类,来为你完成跟消息部分的操作,使用者只需关心核心业务逻辑就可以了。
https://github.com/kklldog/AgileDT 开源不易,大家多多 ✨✨✨
回顾
前面一篇文章我们详细介绍了基于可靠消息的分布式事务。为了更好的理解 AgileDT 的代码,我们还是有必要简单的来回顾下。
[Read More]
.net core with 微服务 分布式事务,可靠消息
前面我们讲了分布式事务的2PC、3PC , TCC 的原理。这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务。特别是 2PC,3PC 他们完全利用数据库的事务能力,在一阶段开始事务后不进提交会严重影响应用程序的并发性能。TCC 一阶段虽然不会阻塞数据库,但是它同样是在尽力追求同时成功同时失败的一致性要求。但是在很多时候,我们的应用程序的核心业务为了追求更高的性能、更高的可用性,可以允许在一段时间内的数据不一致性,只需要在最终时刻数据是一致就可以了。基于以上场景我们可以采用基于可靠消息服务的最终一致性分布式事务处理方案。 总体架构 可靠消息最终一致性的架构上分3个部分: 主动方:主动发起事务的一方,一般是指分布式事务中最先开始执行的那个服务,也是核心业务服务 可靠消息服务:可靠消息服务由关系型数据库、消息队列MQ等组件组成,利用关系型数据库的强一致性特性来持久化消息的状态,利用MQ来保证消息的可靠投递及消费 被动方:被动方订阅MQ的消息,当收到MQ的消息后执行对应的业务 以上是比较粗狂的结构图,下面我们来详细分析一下这个事务的执行过程。 流程 该方案总体流程上可分为以下步骤: 主动方在真正的业务开始前先向可靠消息服务发送一个“待确认”的消息 可靠消息服务收到待确认消息后持久化消息到数据库 如果以上操作成功则主动方开始真正的业务,如果失败则直接放弃执行业务 如果业务执行成功则发送“确认”消息给可靠消息服务,如果执行失败则发送“取消”给可靠消息服务。 如果可靠消息服务收到“确认”消息则更新数据库里的消息记录的状态为“待发送”,如果收到的消息为“取消”则更新消息状态为“已取消” 如果上一步更新的数据库为“待发送”,那么会开始往MQ投递消息,并且更改数据库里的消息记录的状态为“已发送” 上一步往MQ投递消息成功后,MQ会给被动方推送消息。 被动方收到消息后开始处理业务 如果业务处理成功,则被动方对MQ进行ACK回复,则这条消息会从MQ内移除掉 如果业务处理成功,则发送“已完成”消息给可靠消息服务 可靠消息服务收到“已完成”消息后更新数据库消息记录未“已完成” 异常处理 以上我们描述的是一套在理想情况下执行的逻辑。但是分布式系统由于网络的存在,网络的不可靠性会导致我们消息的传递没办法100%成功。我们的可靠消息服务跟主动方、被动方之间的交互也是分布式的,这就需要我们在流程上有很多补偿的机制。以下我们来讨论一些异常情况: 如果步骤1发送“待确认”消息失败,主动方业务不会执行,直接放弃事务,不会有影响 如果步骤1发送“待确认”消息成功,并且可靠消息已经更新“待确认”成功,但是由于网络问题,比如超时,主动方得到的结果是失败,主动方会放弃执行事务,标记为“已取消”。这个时候就会出现可靠消息服务跟主动方的状态出现不一致的情况。 为解决这个问题,我需要主动方提供一个事务状态查询接口,可靠消息服务这边则启动一个定时任务,定时去查这些长时间处于待确认的事务,然后通过主动方的接口确认这些事务是已执行,还是已取消。 如果步骤4,主动方发送“确认”消息失败,可靠消息服务会通过定时任务通过主动方的查询接口去确认状态。 步骤6,投递消息给MQ跟更新状态为“已发送”,是这个流程中至关重要的一步。理想的流程是整个2个操作同时成功同时失败,保持强一致性。网上很多文章都会说“为了保证发送MQ消息跟更新消息状态同时成功同时失败,需要把这个2个步骤写同一个本地事务中”。这是完全不靠谱的,数据库跟MQ本就是2个独立的服务,如果通过一个本地的事务就能保证一致性,那么我们现在讨论的分布式事务毫无意义,直接写在一个本地事务里不就完了么。 写在本地事务内只能尽可能的保证数据库更新跟MQ投递消息同时成功,但是并不能保证100%一致。 以下我们来分2种情况分析失败的情况: ``` 事务开始 send to mq database update 事务结束 先发送 MQ 消息,可能 MQ 消息发送成功,但是database由于某些原因更新失败了。数据库可以回滚,但是通常的MQ没有回滚能力。 事务开始 database...
[Read More]
Agileconfig 1.4.0 发布,全新的发布功能
加入 NCC
先说一个事,AgileConfig 在 7 月底终于通过了 NCC 社区的审核,正式成为了 NCC 大家庭的一员。这对 AgileConfig 来说是一个里程碑,希望加入 NCC 后能更好的帮助到大家。同时责任也更大了,本人会一如既往的对这个项目维护下去,感谢支持。
release-1.4.0
本次1.4.0发布版本是一个比较大更新。解决了 AgileConfig 一些长期存在的功能上的问题。之前版本的发布、回滚只针对单独某个配置,当对某个配置编辑后会记录修改历史,并且发布后的配置修改是实时生效的。这会带来2个比较大的问题:
没有办法追踪“删除”的配置
因为修改历史记录针对的是单个配置,但是当使用删除操作的时候,整个配置会在列表里移除,导致想要恢复的时候都没有入口可以找到这个被删除的配置。
单个配置修改实时上线
之前的版本,当对某个配置修改或者删除后配置会实时同步至客户端。这样会带来一个问题:有的时候我们希望修改好多个配置后同时发布上线,因为配置之间很可能是依赖的关系。
[Read More]
使用 baget 搭建私有 nuget 服务器
现在几乎所有语言都提供包管理工具,比如 JavaScript 的 npm ,Java 的 Maven ,Dart 的 pub 。.Net 程序当然是 NuGet 。NuGet 也出现很多年了,奇怪的是居然还有很多人不知道。 现在软件结构越来越复杂,在多个项目中往往需要共享一些库、组件等等。NuGet 为我们提供了方便的包管理功能。但是 NuGet 默认提供外网公开的服务,如果我们希望在公司内部或者自己家里进行一些库的管理,那么就需要自己来搭建 NuGet 私服。 Nuget 私服有几个工具可以搭建如官方的Nuget.Server 、ProGet 、BaGet 等。这里推荐 BaGet 这个工具,它跨平台又非常轻量化,易于部署,一行 docker 命令就可以运行起来。这里必选吐槽下 Nuget.Server 做为 NuGet 官方提供的一个工具居然还是依赖 Framework 的。 运行 BaGet 服务 BaGet 有多种部署方式。比如可以从 Github 上拉取 release 后的发布文件手工 dotnet 运行,也可以直接使用 docker 容器化部署。现在是容器化的时代,那么当然首先 docker...
[Read More]
.net core with 微服务 分布式事务 tcc 事务
上一次我们讲解了分布式事务的 2PC、3PC 。那么这次我们来理一下 TCC 事务。本次还是讲解 TCC 的原理跟 .NET 其实没有关系。
TCC
Try 准备阶段,尝试执行业务
Confirm 完成业务
Cancel 回滚准备阶段的业务
[Read More]