.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种情况分析失败的情况:
事务开始
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 微服务 - 分布式事务 - 可靠消息最终一致性的更多相关文章
- 使用kafka消息队列解决分布式事务(可靠消息最终一致性方案-本地消息服务)
微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 本文转自:http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一 ...
- .Net Core with 微服务 - 分布式事务 - TCC
上一次我们讲解了分布式事务的 2PC.3PC .那么这次我们来理一下 TCC 事务.本次还是讲解 TCC 的原理跟 .NET 其实没有关系. TCC Try 准备阶段,尝试执行业务 Confirm 完 ...
- .Net Core with 微服务 - 分布式事务 - 2PC、3PC
最近比较忙,好久没更新了.这次我们来聊一聊分布式事务. 在微服务体系下,我们的应用被分割成多个服务,每个服务都配置一个数据库.如果我们的服务划分的不够完美,那么为了完成业务会出现非常多的跨库事务.即使 ...
- Spring Cloud Alibaba | 微服务分布式事务之Seata
Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Green ...
- 微服务分布式事务之LCN、TCC
在亿级流量架构之分布式事务解决方案对比中, 已经简单阐明了从本机事务到分布式事务的演变过程, 文章的最后简单说明了TCC事务, 这儿将会深入了解TCC事务是原理, 以及理论支持, 最后会用Demo举例 ...
- .Net Core with 微服务 - 使用 AgileDT 快速实现基于可靠消息的分布式事务
前面对于分布式事务也讲了好几篇了(可靠消息最终一致性 分布式事务 - TCC 分布式事务 - 2PC.3PC),但是还没有实战过.那么本篇我们就来演示下如何在 .NET 环境下实现一个基于可靠消息的分 ...
- .NET Core with 微服务 - 什么是微服务
微服务是这几年最流行的架构,说起架构不提微服务都不好意思跟人家打招呼.最近想要再梳理一下关于微服务的知识,并且结合本人的一些实践经验来做一些总结与分享.前面会分享一些概念性的东西,后面也会使用.net ...
- spring cloud+dotnet core搭建微服务架构:服务发现(二)
前言 上篇文章实际上只讲了服务治理中的服务注册,服务与服务之间如何调用呢?传统的方式,服务A调用服务B,那么服务A访问的是服务B的负载均衡地址,通过负载均衡来指向到服务B的真实地址,上篇文章已经说了这 ...
- spring cloud+dotnet core搭建微服务架构:配置中心续(五)
前言 上一章最后讲了,更新配置以后需要重启客户端才能生效,这在实际的场景中是不可取的.由于目前Steeltoe配置的重载只能由客户端发起,没有实现处理程序侦听服务器更改事件,所以还没办法实现彻底实现这 ...
随机推荐
- VIM的命令历史
例如有一段文本,将所有CTRL替换为ctrl,将所有A替换为a,也就是执行了:%s/CTRL/ctrl/g和:%s/A/a/g两条命令,然后进行了很多其他编辑,最后关闭VIM. 后来又有一段文本,也需 ...
- windows中抓取hash小结(上)
我上篇随笔说到了内网中横向移动的几种姿势,横向移动的前提是获取了具有某些权限的用户的明文密码或hash,正愁不知道写点啥,那就来整理一下这个"前提"-----如何在windows系 ...
- DVWA靶场之File Inclusion(文件包含)通关
文件包含,未经过严格过滤,将一些恶意构造带入了包含函数,可以使用一些包含函数来包含一些其他乱七八糟的东西,要么导致任意文件读取,要么命令执行 文件包含包括远程文件包含(RFI)和本地文件包含(LFI) ...
- 服务器受到网络攻击时,如何获取请求客户端的真实 IP?
网络攻击 前不久公司遭受了一次网络攻击. 早晨刚到公司,就发现登录接口的调用次数飙升,很快就确认是被恶意攻击,让安全部门做网关入口针对对方 IP 加了限制. 并统一对所有的 IP 加了调用的频率限制. ...
- C#多线程详解(二)
在上一节介绍了线程的基础知识,下面来研究多线程的优先级 using System; using System.Threading;namespace Test{ class TestThread ...
- 利用AOP切面打印项目中每个接口的运行情况
1.前言 AOP切面技术,大家应该都听知道,Spring框架的主要功能之一. AOP切面的用途很广,其中一个常见的用途就是打印接口方法的运行日志和运行时间. 日志对于一个项目很是重要,不仅有助于调错, ...
- freeswitch新增模块API
概述 上一章我们讲解了freeswitch的源码基本结构,以及如何新增一个插件式模块. freeswitch的架构非常适合这种业务开发模式,即以freeswitch的基本功能为开发平台,新增插件式模块 ...
- tensorflow summary demo with linear-model
tf.summary + tensorboard 用来把graph图中的相关信息,如结构图.学习率.准确率.Loss等数据,写入到本地硬盘,并通过浏览器可视化之. 整理的代码如下: import te ...
- k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-5
1.为Flannel生成证书 [root@linux-node1 ~]# vim flanneld-csr.json { "CN": "flanneld", & ...
- Pulsar の 保证消息的顺序性、幂等性和可靠性
原文链接:Pulsar の 保证消息的顺序性.幂等性和可靠性 一.背景 前面两篇文章,已经介绍了关于Pulsar消费者的详细使用和自研的Pulsar组件. 接下来,将简单分析如何保证消息的顺序性.幂等 ...