数据库事务
在说散布式事务之前,我们先从数据库事务说起。
数据库事务可能大家都很熟习,在开发过程中也会经常运用到。但是即便如此,可能关于一些细节问题,很多人依然不分明。比方很多人都晓得数据库事务的几个特性:原子性(Atomicity
)、分歧性( Consistency )、隔离性或独立性(
Isolation)和耐久性(Durabilily),简称就是ACID。但是再往下比方问到隔离性指的是什么的时分可能就不晓得了,或者是晓得隔离性是什么但是再问到数据库完成隔离的都有哪些级别,或者是每个级别他们有什么区别的时分可能就不晓得了。
本文并不打算引见这些数据库事务的这些东西,有兴味能够搜索一下相关材料。不过有一个学问点我们需求理解,就是假设数据库在提交事务的时分忽然断电,那么它是怎样样恢复的呢?
为什么要提到这个学问点呢?
由于散布式系统的中心就是处置各种异常状况,这也是散布式系统复杂的中央,由于散布式的网络环境很复杂,这种“断电”毛病要比单机多很多,所以我们在做散布式系统的时分,最先思索的就是这种状况。这些异常可能有
机器宕机、网络异常、音讯丧失、音讯乱序、数据错误、不牢靠的TCP、存储数据丧失、其他异常等等…
我们接着说本地事务数据库断电的这种状况,它是怎样保证数据分歧性的呢?我们运用SQL Server来举例,我们晓得我们在运用 SQL Server
数据库是由两个文件组成的,一个数据库文件和一个日志文件,通常状况下,日志文件都要比数据库文件大很多。数据库停止任何写入操作的时分都是要先写日志的,同样的道理,我们在执行事务的时分数据库首先会记载下这个事务的redo操作日志,然后才开端真正操作数据库,在操作之前首先会把日志文件写入磁盘,那么当忽然断电的时分,即便操作没有完成,在重新启动数据库时分,数据库会依据当前数据的状况停止undo回滚或者是redo前滚,这样就保证了数据的强分歧性。
接着,我们就说一下散布式事务。
散布式理论
当我们的单个数据库的性能产生瓶颈的时分,我们可能会对数据库停止分区,这里所说的分区指的是物理分区,分区之后可能不同的库就处于不同的效劳器上了,这个时分单个数据库的ACID曾经不能顺应这种状况了,而在这种ACID的集群环境下,再想保证集群的ACID简直是很难到达,或者即便能到达那么效率和性能会大幅降落,最为关键的是再很难扩展新的分区了,这个时分假如再追求集群的ACID会招致我们的系统变得很差,这时我们就需求引入一个新的理论准绳来顺应这种集群的状况,就是
CAP 准绳或者叫CAP定理,那么CAP定理指的是什么呢?
CAP定理
CAP定理是由加州大学伯克利分校Eric Brewer教授提出来的,他指出WEB效劳无法同时满足一下3个属性:
分歧性(Consistency) : 客户端晓得一系列的操作都会同时发作(生效)
可用性(Availability) : 每个操作都必需以可预期的响应完毕
分区容错性(Partition tolerance) : 即便呈现单个组件无法可用,操作仍然能够完成
详细地讲在散布式系统中,在任何数据库设计中,一个Web应用至多只能同时支持上面的两个属性。显然,任何横向扩展战略都要依赖于数据分区。因而,设计人员必需在分歧性与可用性之间做出选择。
这个定理在迄今为止的散布式系统中都是适用的! 为什么这么说呢?
这个时分有同窗可能会把数据库的2PC(两阶段提交)搬出来说话了。OK,我们就来看一下数据库的两阶段提交。
对数据库散布式事务有理解的同窗一定晓得数据库支持的2PC,又叫做 XA Transactions。
MySQL从5.5版本开端支持,SQL Server 2005 开端支持,Oracle 7 开端支持。
其中,XA 是一个两阶段提交协议,该协议分为以下两个阶段:
第一阶段:事务谐和器请求每个触及到事务的数据库预提交(precommit)此操作,并反映能否能够提交.
第二阶段:事务谐和器请求每个数据库提交数据。
其中,假如有任何一个数据库否决此次提交,那么一切数据库都会被请求回滚它们在此事务中的那局部信息。这样做的缺陷是什么呢?
咋看之下我们能够在数据库分区之间取得分歧性。
假如CAP 定理是对的,那么它一定会影响到可用性。
假如说系统的可用性代表的是执行某项操作相关一切组件的可用性的和。那么在两阶段提交的过程中,可用性就代表了触及到的每一个数据库中可用性的和。我们假定两阶段提交的过程中每一个数据库都具有99.9%的可用性,那么假如两阶段提交触及到两个数据库,这个结果就是99.8%。依据系统可用性计算公式,假定每个月43200分钟,99.9%的可用性就是43157分钟,
99.8%的可用性就是43114分钟,相当于每个月的宕机时间增加了43分钟。
以上,能够考证出来,CAP定理从理论上来讲是正确的,CAP我们先看到这里,等会再接着说。
BASE理论
在散布式系统中,我们常常追求的是可用性,它的重要程序比分歧性要高,那么如何完成高可用性呢?
前人曾经给我们提出来了另外一个理论,就是BASE理论,它是用来对CAP定理停止进一步扩大的。BASE理论指的是:
Basically Available(根本可用)
Soft state(软状态)
Eventually consistent(最终分歧性)
BASE理论是对CAP中的分歧性和可用性停止一个权衡的结果,理论的中心思想就是:
我们无法做到强分歧,但每个应用都能够依据本身的业务特性,采用恰当的方式来使系统到达最终分歧性 (Eventual consistency)。
有了以上理论之后,我们来看一下散布式事务的问题。
散布式事务
在散布式系统中,要完成散布式事务,无外乎那几种处理计划。
一、两阶段提交(2PC)
和上一节中提到的数据库XA事务一样,两阶段提交就是运用XA协议的原理,我们能够从下面这个图的流程来很容易的看出中间的一些比方commit和abort的细节。
两阶段提交这种处理计划属于牺牲了一局部可用性来换取的分歧性。在完成方面,在 .NET 中,能够借助 TransactionScop 提供的 API
来编程完成散布式系统中的两阶段提交,比方WCF中就有完成这局部功用。不过在多效劳器之间,需求依赖于DTC来完成事务分歧性,Windows下微软搞的有MSDTC效劳,Linux下就比拟悲剧了。
另外说一句,TransactionScop
默许不能用于异步办法之间事务分歧,由于事务上下文是存储于当前线程中的,所以假如是在异步办法,需求显式的传送事务上下文。
优点: 尽量保证了数据的强分歧,合适对数据强分歧请求很高的关键范畴。(其实也不能100%保证强分歧)
缺陷: 完成复杂,牺牲了可用性,对性能影响较大,不合适高并发高性能场景,假如散布式系统跨接口调用,目前 .NET 界还没有完成计划。
二、补偿事务(TCC)
TCC 其实就是采用的补偿机制,其中心思想是:针对每个操作,都要注册一个与其对应确实认和补偿(撤销)操作。它分为三个阶段:
Try 阶段主要是对业务系统做检测及资源预留
Confirm 阶段主要是对业务系统做确认提交,Try阶段执行胜利并开端执行 Confirm阶段时,默许 Confirm阶段是不会出错的。即:只需Try胜利,Confirm一定胜利。
Cancel 阶段主要是在业务执行错误,需求回滚的状态下执行的业务取消,预留资源释放。
举个例子,假入 Bob 要向 Smith 转账,思绪大约是:
我们有一个本中央法,里面依次调用
1、首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。
2、在 Confirm 阶段,执行远程调用的转账的操作,转账胜利停止冻结。
3、假如第2步执行胜利,那么转账胜利,假如第二步执行失败,则调用远程冻结接口对应的冻结办法 (Cancel)。
优点: 跟2PC比起来,完成以及流程相对简单了一些,但数据的分歧性比2PC也要差一些
缺陷:
缺陷还是比拟明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需求程序员在完成的时分多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处置。
三、本地音讯表(异步确保)
本地音讯表这种完成方式应该是业界运用最多的,其中心思想是将散布式事务拆分红本地事务停止处置,这种思绪是来源于ebay。我们能够从下面的流程图中看出其中的一些细节:
根本思绪就是:
音讯消费方,需求额外建一个音讯表,并记载音讯发送状态。音讯表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后音讯会经过MQ发送到音讯的消费方。假如音讯发送失败,会停止重试发送。
音讯消费方,需求处置这个音讯,并完成本人的业务逻辑。此时假如本地事务处置胜利,标明曾经处置胜利了,假如处置失败,那么就会重试执行。假如是业务上面的失败,能够给消费方发送一个业务补偿音讯,通知消费方停止回滚等操作。
消费方和消费方定时扫描本地音讯表,把还没处置完成的音讯或者失败的音讯再发送一遍。假如有靠谱的自动对账补账逻辑,这种计划还是十分适用的。
这种计划遵照BASE理论,采用的是最终分歧性,笔者以为是这几种计划里面比拟合适实践业务场景的,即不会呈现像2PC那样复杂的完成(当调用链很长的时分,2PC的可用性是十分低的),也不会像TCC那样可能呈现确认或者回滚不了的状况。
优点: 一种十分经典的完成,防止了散布式事务,完成了最终分歧性。在 .NET中 有现成的处理计划。
缺陷: 音讯表会耦合到业务系统中,假如没有封装好的处理计划,会有很多杂活需求处置。
四、MQ 事务音讯
有一些第三方的MQ是支持事务音讯的,比方RocketMQ,他们支持事务音讯的方式也是相似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务音讯的,比方
RabbitMQ 和 Kafka 都不支持。
以阿里的 RocketMQ 中间件为例,其思绪大致为:
第一阶段Prepared音讯,会拿到音讯的地址。
第二阶段执行本地事务,第三阶段经过第一阶段拿到的地址去访问音讯,并修正状态。
也就是说在业务办法内要想音讯队列提交两次恳求,一次发送音讯和一次确认音讯。假如确认音讯发送失败了RocketMQ会定期扫描音讯集群中的事务音讯,这时分发现了Prepared音讯,它会向音讯发送者确认,所以消费方需求完成一个check接口,RocketMQ会依据发送端设置的战略来决议是回滚还是继续发送确认音讯。这样就保证了音讯发送与本地事务同时胜利或同时失败。
遗憾的是,RocketMQ并没有 .NET 客户端。有关 RocketMQ的更多音讯,大家能够查看
这篇博客
优点: 完成了最终分歧性,不需求依赖本地数据库事务。
缺陷: 完成难度大,主流MQ不支持,没有.NET客户端,RocketMQ事务音讯局部代码也未开源。
五、Sagas 事务模型
Saga事务模型又叫做长时间运转的事务(Long-running-transaction), 它是由普林斯顿大学的H.Garcia-
Molina等人提出,它描绘的是另外一种在没有两阶段提交的的状况下处理散布式系统中复杂的业务事务问题。你能够在 这里
看到 Sagas
相关论文。
我们这里说的是一种基于 Sagas 机制的工作流事务模型,这个模型的相关理论目前来说还是比拟新的,以致于百度上简直没有什么相关材料。
该模型其中心思想就是拆分散布式系统中的长事务为多个短事务,或者叫多个本地事务,然后由 Sagas
工作流引擎担任谐和,假如整个流程正常完毕,那么就算是业务胜利完成,假如在这过程中完成失败,那么Sagas工作流引擎就会以相反的次第调用补偿操作,重新停止业务回滚。
比方我们一次关于购置旅游套餐业务操作触及到三个操作,他们分别是预定车辆,预定宾馆,预定机票,他们分别属于三个不同的远程接口。可能从我们程序的角度来说他们不属于一个事务,但是从业务角度来说是属于同一个事务的。
他们的执行次第如上图所示,所以当发作失败时,会依次停止取消的补偿操作。
由于长事务被拆分了很多个业务流,所以 Sagas 事务模型最重要的一个部件就是工作流或者你也能够叫流程管理器(Process
Manager),工作流引擎和Process
Manager固然不是同一个东西,但是在这里,他们的职责是相同的。在选择工作流引擎之后,最终的代码或许看起来是这样的
SagaBuilder saga = SagaBuilder.newSaga("trip")
.activity("Reserve car", ReserveCarAdapter.class)
.compensationActivity("Cancel car", CancelCarAdapter.class)
.activity("Book hotel", BookHotelAdapter.class)
.compensationActivity("Cancel hotel", CancelHotelAdapter.class)
.activity("Book flight", BookFlightAdapter.class)
.compensationActivity("Cancel flight", CancelFlightAdapter.class)
.end()
.triggerCompensationOnAnyError();
camunda.getRepositoryService().createDeployment()
.addModelInstance(saga.getModel())
.deploy();
这里
有一个 C# 相关示例,有兴味的同窗能够看一下。
优缺陷这里我们就不说了,由于这个理论比拟新,目前市面上还没有什么处理计划,即便是 Java 范畴,我也没有搜索的太多有用的信息。
散布式事务处理计划:CAP
上面引见的那些散布式事务的处置计划你在其他中央或许也能够看到,但是并没有相关的实践代码或者是开源代码,所以算不上什么干货,下面就放干货了。
在 .NET
范畴,似乎没有什么现成的关于散布式事务的处理计划,或者说是有但未开源。具笔者理解,有一些公司内部其实是有这种处理计划的,但是也是作为公司的一个中心产品之一,并未开源…
鉴于以上缘由,所以博主就打算本人写一个并且开源出来,所以从17年初就开端做这个事情,然后花了大半年的时间在不断不时完善,就是下面这个 CAP。
Github CAP :这里的 CAP 就不是 CAP 理论了,而是一个
.NET 散布式事务处理计划的名字。
细致引见:
http://www.cnblogs.com/savorboard/p/cap.html
相关文档:
http://www.cnblogs.com/savorboard/p/cap-document.html
夸大的是,这个处理计划是具有可视化界面(Dashboard)的,你能够很方面的看到哪些音讯执行胜利,哪些音讯执行失败,到底是发送失败还是处置失败,一眼便知。
最夸大的是,这个处理计划的可视化界面还提供了 实时动态图表
,这样不但能够看到实时的音讯发送及处置状况,连当前的系统处置音讯的速度都能够看到,还能够看到过去24小时内的历史音讯吞吐量。
最最夸大的是,这个处理计划的还帮你集成了 Consul 做散布式节点发现和注册还有心跳检查,你随时能够看到其他的节点的情况。
最最最夸大的是,你以为你看其他节点的数据要登录到其他节点的Dashboard控制台看?错了,你随意翻开其中恣意一个节点的Dashboard,点一下就能够切换到你想看的节点的控制台界面了,就像你看本地的数据一样,他们是完整去中心化的。
你以为这些就够了?不,远远不止:
CAP 同时支持 RabbitMQ,Kafka 等音讯队列
CAP 同时支持 SQL Server, MySql, PostgreSql 等数据库
CAP Dashboard 同时支持中文和英文界面双言语,妈妈再也不用担忧我看不懂了
CAP 提供了丰厚的接口能够供扩展,什么序列化了,自定义处置了,自定义发送了通通不在话下
CAP 基于MIT开源,你能够虽然拿去做二次开发。(记得保存MIT的License)
这下你以为我说完了? 不!
你完整能够把 CAP 当做一个 EventBus 来运用,CAP具有优秀的音讯处置才能,不要担忧瓶颈会在CAP,那是永远不可能,
由于你随时能够在配置中指定CAP处置的音讯运用的进程数, 只需你的数据库配置足够高…
说了这么多,口干舌燥的,你不 Star 一下给个肉体上的支持说不过去吧? _
2号传送门: https://github.com/dotnetcore/CAP
不 Star 也没关系,我选择原谅你~
总结
经过本文我们理解到两个散布式系统的理论,他们分别是CAP和BASE
理论,同时我们也总结并比照了几种散布式合成计划的优缺陷,散布式事务自身是一个技术难题,是没有一种圆满的计划应对一切场景的,详细还是要依据业务场景去抉择吧。
然后我们引见了一种基于本地音讯的的散布式事务处理计划CAP。
假如你觉得本篇文章对您有协助的话,感激您的【引荐】。
假如你对 .NET Core 有兴味的话能够关注我,我会定期的在博客分享我的学习心得。
引荐阅读
应用 ShardingSphere-JDBC 完成分库分表理论
Spring Boot 构建多租户 SaaS 平台中心技术指南
Redis 缓存和MySQL数据分歧性计划详解
Nginx 限流配置
深化探秘 Netty、Kafka中的零拷贝技术!
学习材料分享
12 套 微效劳、Spring Boot、Spring Cloud 中心技术材料,这是局部材料目录:
Spring Security 认证与受权
Spring Boot 项目实战(中小型互联网公司后台效劳架构与运维架构)
Spring Boot 项目实战(企业权限管理项目))
Spring Cloud 微效劳架构项目实战(散布式事务处理计划)