前面我们讲了分布式事务的2PC、3PCTCC 的原理。这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务。特别是 2PC,3PC 他们完全利用数据库的事务能力,在一阶段开始事务后不进提交会严重影响应用程序的并发性能。TCC 一阶段虽然不会阻塞数据库,但是它同样是在尽力追求同时成功同时失败的一致性要求。但是在很多时候,我们的应用程序的核心业务为了追求更高的性能、更高的可用性,可以允许在一段时间内的数据不一致性,只需要在最终时刻数据是一致就可以了。基于以上场景我们可以采用基于可靠消息服务的最终一致性分布式事务处理方案。

总体架构

可靠消息最终一致性的架构上分3个部分:

  1. 主动方:主动发起事务的一方,一般是指分布式事务中最先开始执行的那个服务,也是核心业务服务

  2. 可靠消息服务:可靠消息服务由关系型数据库、消息队列MQ等组件组成,利用关系型数据库的强一致性特性来持久化消息的状态,利用MQ来保证消息的可靠投递及消费

  3. 被动方:被动方订阅MQ的消息,当收到MQ的消息后执行对应的业务 以上是比较粗狂的结构图,下面我们来详细分析一下这个事务的执行过程。

流程

该方案总体流程上可分为以下步骤:

  1. 主动方在真正的业务开始前先向可靠消息服务发送一个“待确认”的消息

  2. 可靠消息服务收到待确认消息后持久化消息到数据库

  3. 如果以上操作成功则主动方开始真正的业务,如果失败则直接放弃执行业务

  4. 如果业务执行成功则发送“确认”消息给可靠消息服务,如果执行失败则发送“取消”给可靠消息服务。

  5. 如果可靠消息服务收到“确认”消息则更新数据库里的消息记录的状态为“待发送”,如果收到的消息为“取消”则更新消息状态为“已取消”

  6. 如果上一步更新的数据库为“待发送”,那么会开始往MQ投递消息,并且更改数据库里的消息记录的状态为“已发送”

  7. 上一步往MQ投递消息成功后,MQ会给被动方推送消息。

  8. 被动方收到消息后开始处理业务

  9. 如果业务处理成功,则被动方对MQ进行ACK回复,则这条消息会从MQ内移除掉

  10. 如果业务处理成功,则发送“已完成”消息给可靠消息服务

  11. 可靠消息服务收到“已完成”消息后更新数据库消息记录未“已完成”

异常处理

以上我们描述的是一套在理想情况下执行的逻辑。但是分布式系统由于网络的存在,网络的不可靠性会导致我们消息的传递没办法100%成功。我们的可靠消息服务跟主动方、被动方之间的交互也是分布式的,这就需要我们在流程上有很多补偿的机制。以下我们来讨论一些异常情况:

  1. 如果步骤1发送“待确认”消息失败,主动方业务不会执行,直接放弃事务,不会有影响

  2. 如果步骤1发送“待确认”消息成功,并且可靠消息已经更新“待确认”成功,但是由于网络问题,比如超时,主动方得到的结果是失败,主动方会放弃执行事务,标记为“已取消”。这个时候就会出现可靠消息服务跟主动方的状态出现不一致的情况。
    为解决这个问题,我需要主动方提供一个事务状态查询接口,可靠消息服务这边则启动一个定时任务,定时去查这些长时间处于待确认的事务,然后通过主动方的接口确认这些事务是已执行,还是已取消。

  3. 如果步骤4,主动方发送“确认”消息失败,可靠消息服务会通过定时任务通过主动方的查询接口去确认状态。

  4. 步骤6,投递消息给MQ跟更新状态为“已发送”,是这个流程中至关重要的一步。理想的流程是整个2个操作同时成功同时失败,保持强一致性。网上很多文章都会说“为了保证发送MQ消息跟更新消息状态同时成功同时失败,需要把这个2个步骤写同一个本地事务中”。这是完全不靠谱的,数据库跟MQ本就是2个独立的服务,如果通过一个本地的事务就能保证一致性,那么我们现在讨论的分布式事务毫无意义,直接写在一个本地事务里不就完了么。
    写在本地事务内只能尽可能的保证数据库更新跟MQ投递消息同时成功,但是并不能保证100%一致。
    以下我们来分2种情况分析失败的情况:

事务开始
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

关注我的公众号一起玩转技术

.Net Core with 微服务 - 可靠消息最终一致性分布式事务相关推荐

  1. 《深入理解分布式事务》第九章 可靠消息最终一致性分布式事务原理

    <深入理解分布式事务>第九章 可靠消息最终一致性分布式事务原理 文章目录 <深入理解分布式事务>第九章 可靠消息最终一致性分布式事务原理 一.基本原理 二.本地消息表 1.实现 ...

  2. 《深入理解分布式事务》第六章 最终一致性分布式事务解决方案

    <深入理解分布式事务>第六章 最终一致性分布式事务解决方案 文章目录 <深入理解分布式事务>第六章 最终一致性分布式事务解决方案 一.最终一致性分布式事务概述 1.典型方案 2 ...

  3. 基于可靠消息方案的分布式事务(四):接入Lottor服务

    在上一篇文章中,通过Lottor Sample介绍了快速体验分布式事务Lottor.本文将会介绍如何将微服务中的生产方和消费方服务接入Lottor. 场景描述 生产方:User服务 消费方:Auth服 ...

  4. 消费消息删除_【进阶之路】可靠消息最终一致性解决方案

    导言 大家好,我是南橘,从接触java到现在也有差不多两年时间了,两年时间,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西.知识越分享越值钱,我这段时间总结 ...

  5. 可靠消息最终一致性设计_如何最终启动您的设计产品组合

    可靠消息最终一致性设计 It's not a secret that most designers procrastinate on their portfolios whether it is to ...

  6. nosql简答什么是最终一致性_可靠消息最终一致性方案中预发送作用是什么

    可靠消息最终一致性方案的核心流程 ①上游服务投递消息 如果要实现可靠消息最终一致性方案,一般你可以自己写一个可靠消息服务,实现一些业务逻辑. 首先,上游服务需要发送一条消息给可靠消息服务.这条消息说白 ...

  7. 基于可靠消息方案的分布式事务:Lottor介绍

    前言:笔者最近实现了基于可靠消息方案的分布式事务:Lottor.本文将会介绍Lottor的概况,在后续系列文章介绍具体的实现,欢迎关注. 分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源 ...

  8. 弹性事务框架ETF4J——面向Java微服务的交易最终一致性解决方案

    此文旨在介绍 弹性事务框架ETF4J 背后的一些基本概念和想法, 后续修改会同步更新到该项目github主页 https://github.com/VincentLiSH/elastic-transa ...

  9. SpringCloud Alibaba 微服务架构(十一)- 分布式事务解决方案及理论基础篇

    前言 在传统的单体应用架构中,例如经典的SSM,项目会采用分层架构模式:数据库访问层.业务逻辑层.控制层,从前端到后台所有的代码都是一个或者几个开发者去完成,该架构模式没有对我们业务逻辑代码实现拆分. ...

最新文章

  1. Linux文件类型有哪些?
  2. OpenCV使用inRange的阈值操作Thresholding Operations
  3. Spring和JSF集成:分页
  4. 【Python3网络爬虫开发实战】1.6.1-Flask的安装
  5. Airflow 中文文档:Lineage
  6. 带哨兵节点的链_Redis 哨兵节点之间相互自动发现机制(自动重写哨兵节点的配置文件)...
  7. C# 客户端时间校准
  8. ecshop怎样在新主页模板里调用首页主广告
  9. 从无线安全到内网渗透[1]
  10. 一个多道批处理系统中仅有 P1 和 P2 两个作业
  11. 开发低功耗蓝牙4.0血压计连接与收发数据
  12. excel生成随机数 / random number in excel
  13. unity3d人物跳_Unity人物跳跃效果
  14. kubeadm join时报错Unauthorized
  15. 揭秘APP软件开发者百万富翁之路:造程序的工厂
  16. SQL 语句查看表结构
  17. dreamweaver php 动态教程,利用DreamweaverCS5制作一个含有动态标题的教程
  18. 重庆北大青鸟ACCP软件工程师课程内容有哪些?
  19. 2021-08-09 程序员的自我修养
  20. python -- 封装token

热门文章

  1. SpringMVC核心分发器DispatcherServlet分析[附带源码分析]
  2. 01. Node js Hello world
  3. Hadoop分布式文件系统:架构和设计要点
  4. wxPython:登录工具
  5. 高精度(压位+判负数+加减乘+读写)
  6. Oracle数据库查询用 where in 查询的项超过1000条的解决方案
  7. canvas特效代码详解(2)
  8. Android 使用XmlPullParser解析xml
  9. ubuntu apt-get常用命令
  10. raspberry pi_在月光下将Raspberry Pi变成蒸汽机