前面我们讲了分布式事务的2PC、3PC , TCC 的原理。这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务。特别是 2PC,3PC 他们完全利用数据库的事务能力,在一阶段开始事务后不进提交会严重影响应用程序的并发性能。TCC 一阶段虽然不会阻塞数据库,但是它同样是在尽力追求同时成功同时失败的一致性要求。但是在很多时候,我们的应用程序的核心业务为了追求更高的性能、更高的可用性,可以允许在一段时间内的数据不一致性,只需要在最终时刻数据是一致就可以了。基于以上场景我们可以采用基于可靠消息服务的最终一致性分布式事务处理方案。
可靠消息最终一致性的架构上分3个部分:
该方案总体流程上可分为以下步骤:
以上我们描述的是一套在理想情况下执行的逻辑。但是分布式系统由于网络的存在,网络的不可靠性会导致我们消息的传递没办法100%成功。我们的可靠消息服务跟主动方、被动方之间的交互也是分布式的,这就需要我们在流程上有很多补偿的机制。以下我们来讨论一些异常情况:
事务开始 1. send to mq 2. database update 事务结束
先发送 MQ 消息,可能 MQ 消息发送成功,但是database由于某些原因更新失败了。数据库可以回滚,但是通常的MQ没有回滚能力。
事务开始 1. database update 2. send to mq 事务结束
先更新数据库,再发送 MQ 消息,同样会有问题。就算1,2都执行成功了,但是事务是需要提交的,数据库有可能在提交阶段失败,数据库是可以回滚,但是 MQ 的消息已经发出去了,它并没有回滚的能力。
为了解决这个问题,我们同样需要补偿机制。在可靠消息服务一侧开启定时任务,定时去查询那些长期处于“待发送\已发送”的事务,再次对 MQ 进行投递消息。这个机制有可能造成被动方重复收到 MQ 的消息,这就需要被动方处理业务的时候要进行幂等处理。
通过以上我们详细介绍了可靠消息最终一致性事务解决方案的总体结构跟执行的流程,以及对异常情况的一些补偿方法,总体流程上还是比较清晰简单的。但是可靠消息最终一致性方案在使用上也是具有比较强的局限性,因为它的异步特性跟有可能出现的高延时性不适合处理一些敏感业务。比如它适合处理消费新增积分场景,但是不合适处理积分兑换礼品的场景。因为如果积分扣减延迟了,那么用户就可能兑换超出本身积分多的多的礼品。所以我们选择分布式事务的时候还需根据场景来进行选择。
好了讲了这么多分布式事务的原理,下一期我们使用 .NET 真正的实现一个分布式事务,敬请期待。
.Net Core with 微服务 - 什么是微服务
.Net Core with 微服务 - 架构图
.Net Core with 微服务 - Ocelot 网关
.Net Core with 微服务 - Consul 注册中心
.Net Core with 微服务 - Seq 日志聚合
.Net Core with 微服务 - Elastic APM
.Net Core with 微服务 - Consul 配置中心
.Net Core with 微服务 - Polly 熔断降级
.Net Core with 微服务 - 分布式事务 - 2PC、3PC
.Net Core with 微服务 - 分布式事务 - TCC