前言开始我们今天的话题,说说分布式事务,或者说我眼中的分布式事务,因为每个人对它们的理解可能不一样。分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构都会涉及到的东西。尤其是在微服务架构中,几乎可以说是避无可避。这篇文章会简单的讲一遍分布式事务。在讲分布式事务之前,我们先从数据库事务说起。数据库事务大家可能都不陌生,在开发过程中经常会用到。但即便如此,对于一些细节,很多人可能还是不清楚。例如,很多人都知道数据库事务的几个特性:原子性(Atomicity)、一致性(Consistency)、隔离或独立性(Isolation)和持久性(Durabilily),简称ACID。但是再往下,比如你问隔离指的是什么,你可能不知道,或者你知道什么是隔离,但是再问数据库隔离有哪些级别,或者各个级别之间有什么区别?什么时候你可能不知道。本文无意介绍这些关于这些数据库事务的东西。有兴趣的可以搜索相关资料。但是有一个知识点我们需要了解,那就是如果在提交事务的时候数据库突然断电了,如何恢复呢?为什么要提这个知识点呢?因为分布式系统的核心就是要处理各种异常情况,这也是分布式系统复杂的地方,因为分布式网络环境非常复杂,“掉电”故障比单机多很多,所以我们在做分布式系统设计的时候,首先要考虑的就是这个。这些异常可能包括机器宕机、网络异常、消息丢失、消息乱序、数据错误、不可靠的TCP、存储数据丢失、其他异常等等……下面说说本地事务数据库供电的情况off,它是如何保证数据一致性的?我们以SQLServer为例。我们知道,我们使用的SQLServer数据库由两个文件组成,一个是数据库文件,一个是日志文件。通常,日志文件比数据库文件大得多。当数据库执行任何写操作时,它必须首先写入日志。同理,当我们执行事务时,数据库会先记录事务的重做操作日志,然后才开始真正操作数据库。在操作之前,我们会先将日志文件写入磁盘,然后当突然断电时,即使操作没有完成,当数据库重启时,数据库也会根据当前数据情况,从而保证数据的强一致性。接下来说一下分布式事务。另外整理了分布式事务系列的所有面试题和答案。微信搜索Java技术栈,后台发送:面试,可以在线阅读。分布式理论当我们的单体数据库出现性能瓶颈的时候,我们可能会对数据库进行分区。这里所说的分区是指物理分区。分区后,不同的库可能在不同的服务器上。这时单个数据库的ACID已经不能适应这种情况,而在这种ACID集群环境下,几乎很难保证集群的ACID达到,或者即使能够达到,效率和性能会大大降低。最重要的是很难扩展新的分区。这时候如果追求集群的ACID,我们的系统就会变差。这时候就需要引入一个新的理论原理来适应这种集群情况,就是CAP原理或者叫CAP定理,那么CAP定理是什么意思呢?CAP定理CAP定理是由加州大学伯克利分校的EricBrewer教授提出的。他指出WEB服务不能同时满足以下三个属性:一致性(Consistency):客户端知道一系列操作会同时发生(生效)可用性(Availability):每个操作必须以可预测的反应。分区容忍:即使单个组件变得不可用,仍然可以完成操作。具体来说,在分布式系统中,在任何数据库设计中,一个Web应用最多只能同时支持以上两个属性。显然,任何横向扩展策略都依赖于数据分区。因此,设计师必须在一致性和可用性之间做出选择。这个定理至今适用于分布式系统!你为什么这么说?这时候可能会有同学说到数据库的2PC(two-phasecommit)。OK,我们来看一下数据库的两阶段提交。对数据库分布式事务有了解的同学一定知道数据库支持的2PC,也就是XATransactions。从5.5版本开始支持MySQL,支持SQLServer2005,支持Oracle7。其中,XA是一个两阶段提交协议,分为以下两个阶段:第一阶段:事务协调器要求事务中涉及的每个数据库预先提交(precommit)这个操作,并反映是否可以提交.第二阶段:事务协调器要求每个数据库提交数据。其中,如果任何数据库否决提交,所有数据库都将被要求回滚他们的部分事务。这样做的缺点是什么?乍一看,我们可以获得跨数据库分区的一致性。如果CAP定理成立,那么它一定会影响可用性。如果系统的可用性表示与操作执行相关的所有组件的可用性总和。那么在两阶段提交的过程中,可用性表示所涉及的每个数据库中可用性的总和。我们假设在两阶段提交过程中每个数据库的可用性都是99.9%,那么如果两阶段提交涉及两个数据库,那么结果就是99.8%。根据系统可用性计算公式,假设每月43200分钟,99.9%可用性为43157分钟,99.8%可用性为43114分钟,相当于每月增加43分钟停机时间。综上所述,可以验证CAP定理在理论上是正确的。CAP先说到这里,后面再说。BASE理论在分布式系统中,我们往往追求可用性,其重要的程序高于一致性,那么如何实现高可用性呢?前人为我们提出了另一种理论,即BASE理论,用来进一步扩展CAP定理。BASE理论是指:基本可用(basicallyavailable)软状态(softstate)最终一致性(finalconsistency)BASE理论是CAP中一致性和可用性权衡的结果。该理论的核心思想是:我们无法实现强一致性,而是各个应用可以根据自己的业务特点采用合适的方法使系统实现最终一致性。有了上面的理论,我们再来看看分布式事务的问题。分布式事务在分布式系统中,要实现分布式事务,只有几种解决方案。1、两阶段提交(2PC)与上一节提到的数据库XA事务相同。两阶段提交是使用XA协议的原则。从下图的流程我们可以很容易的看到commit和abort等中间的一些细节。两阶段提交是一种牺牲部分可用性来换取一致性的方案。在实现上,在.NET中,可以使用TransactionScop提供的API来编写分布式系统中的两阶段提交,如WCF,实现了这部分功能。但是在多台服务器之间,需要依赖DTC来完成事务的一致性。微软在Windows下提供了MSDTC服务,但是在Linux下就悲剧了。另外,TransactionScope默认不能用于异步方法间的事务一致性,因为事务上下文保存在当前线程中,所以如果是在异步方法中,需要显式传递事务上下文。优点:尽可能保证数据的强一致性,适用于对数据一致性要求高的关键领域。(其实强一致性并不能100%保证)缺点:实现复杂,牺牲易用性,对性能影响较大,不适合高并发高性能场景。如果分布式系统跨接口调用,目前.NET世界还没有实现计划。2.补偿交易(TCC)TCC其实就是采用的补偿机制,其核心思想是:对于每一个操作,都要注册一个对应的确认和补偿(撤销)操作。分为三个阶段:Try阶段主要是检测业务系统和预留资源。Confirm阶段主要是对业务系统进行确认和提交。当Try阶段执行成功并启动Confirm阶段时,默认的Confirm阶段是不会出错的。即:只要Try成功,Confirm就一定成功。Cancel阶段主要是在业务执行错误需要回滚时取消业务,释放预留资源。比如Bob要给Smith转钱,思路大概是:我们有一个本地方法,依次调用1。首先,在Try阶段,我们需要调用远程接口来冻结Smith和Bob的钱。2、Confirm阶段,进行远程调用的转账操作,转账解冻成功。3、如果第二步执行成功,则转账成功。如果第二步失败,则调用远程冻结接口对应的解冻方法(Cancel)。优点:与2PC相比,实现和过程都比较简单,但是数据一致性也比2PC差。缺点:缺点比较明显,有可能在第2步和第3步失败。TCC是一种应用层的补偿方式,所以程序员在实现的时候需要写很多补偿代码。在某些场景下,一些业务流程可能没有很好地被TCC定义和处理。3.本地消息表(异步保证)这种本地消息表的实现方式应该是业界用的最多的。它的核心思想是将分布式事务拆分成本地事务进行处理。这个想法来自eBay。我们可以从下面的流程图中看到一些细节:基本思路是:消息生产者需要额外创建一个消息表,记录消息的发送状态。消息表和业务数据必须在事务中提交,也就是说必须在数据库中。然后消息会通过MQ发送给消息的消费者。如果消息发送失败,将重试。消息消费者需要对消息进行处理,完成自己的业务逻辑。此时如果本地事务处理成功,说明处理成功。如果处理失败,将重试执行。如果是业务失败,可以向生产者发送业务补偿消息,通知生产者进行回滚等操作。生产者和消费者定期扫描本地消息表,重新发送未处理的消息或失败的消息。如果有靠谱的自动对账和补货逻辑,这个方案还是很实用的。本方案遵循BASE理论,采用最终一致性。作者认为这些方案更适合实际业务场景,即不会像2PC那样复杂的实现(当调用链很长时,2PC的可用性很低),不会有确认或回滚像TCC这样的失败。优点:非常经典的实现,避免了分布式事务,实现了最终一致性。.NET中有现成的解决方案。缺点:消息表会和业务系统耦合。如果没有打包的解决方案,就会有很多杂事要处理。4、MQ事务消息有一些第三方MQ支持事务消息,比如RocketMQ。它们支持事务性消息的方式类似于采用的两阶段提交,但是市面上一些主流的MQ并不支持事务性消息。比如RabbitMQ和Kafka都不支持。以阿里的RocketMQ中间件为例,思路大致是这样的:在Prepared消息的第一阶段,会获取消息的地址。第二阶段执行本地事务,第三阶段使用第一阶段获得的地址访问消息和修改状态。也就是说,在业务方法中,你要向消息队列提交两个请求,一个发送消息,一个确认消息。如果确认消息发送失败,RocketMQ会周期性扫描消息集群中的事务消息。当它此时发现一条Prepared消息时,它会向消息发送者确认。因此生产者需要实现一个校验接口,RocketMQ会根据发送方设置的策略进行校验。决定是回滚还是继续发送确认消息。这样可以确保消息发送成功或失败与本地事务同时发生。不幸的是,RocketMQ没有.NET客户端。优点:实现最终一致性,不需要依赖本地数据库事务。缺点:实现难度大,主流MQ不支持,没有.NET客户端,RocketMQ事务消息部分代码不开源。五、Sagas事务模型Saga事务模型也称为长运行事务(Long-running-transaction),由普林斯顿大学的H.Garcia-Molina等人提出。它描述了另一种无需两阶段提交的事务解决分布式系统中复杂的业务事务问题。我们这里说的是一种基于Sagas机制的工作流事务模型。该模型的相关理论目前还比较新,以至于百度上几乎没有相关资料。该模型的核心思想是将分布式系统中的长事务拆分为多个短事务,或者多个本地事务,然后由Sagas工作流引擎负责协调。如果整个流程正常结束,则认为业务顺利完成。如果在此过程中执行失败,Sagas工作流引擎会倒序调用补偿操作,再次回滚业务。比如我们购买旅游套票的业务操作涉及三个操作,分别是订车、订酒店、订机票,它们属于三个不同的远程接口。可能从我们程序的角度来看它们不属于一个事务,但是从业务的角度来看它们属于同一个事务。它们的执行顺序如上图所示,所以当出现故障时,会依次执行取消的补偿操作。因为长事务被拆分成很多业务流,所以Sagas事务模型中最重要的部分就是工作流或者你也可以称之为流程管理器(ProcessManager)。虽然工作流引擎和流程管理器不是一回事,但是在这里,它们的职责是一样的。选择工作流引擎后,最终代码可能如下所示(“预订酒店”,BookHotelAdapter.class).compensationActivity(“取消酒店”,CancelHotelAdapter.class).activity(“预订航班”,BookFlightAdapter.class).compensationActivity(“取消航班”,CancelFlightAdapter.class)。结束()这里先不说优缺点,因为这个理论比较新,目前还没有解决方案,甚至在Java世界里,也没怎么搜索过有用的资料。分布式事务解决方案:大家可能在其他地方也看到了CAP推出的分布式事务处理解决方案,但是没有相关的实际代码或者开源代码,所以不是干货,下面是干货上来的。在.NET领域,分布式事务似乎没有现成的解决方案,或者有但不开源。笔者了解到有些公司内部其实也有这种解决方案,但是也是公司的核心产品之一,而且没有开源……鉴于以上原因,博主打算写一个和开源它。所以我在2017年初开始做这个,然后花了大半年的时间在持续改进上,也就是下面的CAP。GithubCAP:这里的CAP并不是CAP理论,而是一种.NET分布式事务解决方案的名称。详细介绍:http://www.cnblogs.com/savorb...相关文档:http://www.cnblogs.com/savorb...夸张的是这个方案有一个可视化界面(Dashboard),你可以轻松查看哪些消息执行成功,哪些消息执行失败,是否发送或处理失败,一目了然。最夸张的是,该方案的可视化界面还提供了实时动态图表,让你不仅可以看到实时的消息发送和处理状态,还可以看到当前系统对消息的处理速度,并且可以还可以查看过去24小时。以小时为单位的历史消息吞吐量。最夸张的是,这个方案还集成了Consul,为你进行分布式节点发现和注册,以及心跳检查。您可以随时查看其他节点的状态。最夸张的是,你觉得需要登录其他节点的Dashboard控制台才能查看其他节点的数据吗?错了,你只要打开任意一个节点的Dashboard,就可以一键切换到你想看的节点的控制台界面。就像您查看本地数据一样,它们是完全去中心化的。你觉得这些够了吗?不,远不止于此:CAP同时支持RabbitMQ和Kafka等消息队列。CAP还支持SQLServer、MySql、PostgreSql等数据库。CAPDashboard同时支持中英文双语界面。妈妈再也不用担心我听不懂了。CAP提供了丰富的接口,可以进行扩展,序列化,自定义处理,自定义发送都很容易。CAP基于MIT开源,您可以使用它进行二次开发。(记得保留MIT许可证)现在你认为我完成了吗?不!另外,MQ系列面试题及答案已经全部整理完毕,微信搜索Java技术栈,后台发送:面试,即可在线阅读。您可以将CAP用作EventBus。CAP具有出色的消息处理能力。不用担心CAP中的瓶颈。你的数据库配置够高了...传送门二:https://github.com/dotnetcore...总结通过这篇文章,我们了解了两种分布式系统理论,它们是CAP和BASE理论,我们也了解了它总结比较了几种分布式分解方案的优缺点。分布式事务本身就是一个技术问题,没有适用于所有场景的完美解决方案。具体要根据业务场景来决定。然后介绍CAP,一种基于本地消息的分布式事务解决方案。作者:Savorboard本文地址:http://www.cnblogs.com/savorb...近期热文推荐:1.1,000+Java面试题及答案(2021最新版)/else,试试策略模式,是可口的!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.5发布,深色模式太炸了!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
