现今互联网界,分布式系统和微服务架构盛行。业界著名的CAP理论也告诉咱们,在设计和实现一个分布式系统时,须要将数据一致性、系统可用性和分区容忍性放在一块儿考虑。算法
一、CAP理论数据库
在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)3 个要素最多只能同时知足两个,不可兼得。其中,分区容忍性又是不可或缺的。网络
一致性:分布式环境下多个节点的数据是否强一致。架构
可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。并发
分区容忍性:特指对网络分区的容忍性。app
举例:Cassandra、Dynamo 等,默认优先选择AP,弱化C;HBase、MongoDB 等,默认优先选择CP,弱化A。异步
二、BASE 理论分布式
核心思想:ide
基本可用(Basically Available):指分布式系统在出现故障时,容许损失部分的可用性来保证核心可用。微服务
软状态(Soft State):指容许分布式系统存在中间状态,该中间状态不会影响到系统的总体可用性。
最终一致性(Eventual Consistency):指分布式系统中的全部副本数据通过必定时间后,最终可以达到一致的状态。
数据的一致性模型能够分红如下 3 类:
强一致性:数据更新成功后,任意时刻全部副本中的数据都是一致的,通常采用同步的方式实现。
弱一致性:数据更新成功后,系统不承诺当即能够读到最新写入的值,也不承诺具体多久以后能够读到。
最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺当即能够返回最新写入的值,可是保证最终会返回上一次更新操做的值。
分布式系统数据的强一致性、弱一致性和最终一致性能够经过Quorum NRW算法分析。
分布式事务的目的是保障分布式存储中数据一致性,而跨库事务会遇到各类不可控制的问题,如个别节点宕机,像单机事务同样的ACID是没法奢望的。一、Two/Three Phase Commit2PC,中文叫两阶段提交。在分布式系统中,每一个节点虽然能够知晓本身的操做时成功或者失败,却没法知道其余节点的操做的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,须要引入一个做为协调者的组件来统一掌控全部节点(称做参与者)的操做结果并最终指示这些节点是否要把操做结果进行真正的提交。两阶段提交的算法以下:第一阶段:
第二阶段:
两段提交最大的问题就是第3)项,若是第一阶段完成后,参与者在第二阶没有收到决策,那么数据结点会进入“不知所措”的状态,这个状态会block住整个事务。也就是说,协调者Coordinator对于事务的完成很是重要,Coordinator的可用性是个关键。因些,咱们引入三段提交,三段提交在Wikipedia上的描述以下,他把二段提交的第一个段break成了两段:询问,而后再锁资源。最后真正提交。三段提交的核心理念是:在询问的时候并不锁定资源,除非全部人都赞成了,才开始锁资源。但三阶段提交也存在一些缺陷,要完全从协议层面避免数据不一致,能够采用Paxos或者Raft 算法。目前两阶段提交、三阶段提交存在以下的局限性,并不适合在微服务架构体系下使用:
二、Try Confirm Cancel(TCC)
一个完整的TCC业务由一个主业务服务和若干个从业务服务组成,主业务服务发起并完成整个业务活动,TCC模式要求从服务提供三个接口:Try、Confirm、Cancel。
Try:完成全部业务检查,预留必须业务资源。
Confirm:真正执行业务,不做任何业务检查;只使用Try阶段预留的业务资源;Confirm操做知足幂等性。
Cancel:释放Try阶段预留的业务资源;Cancel操做知足幂等性。
整个TCC业务分红两个阶段完成:
第一阶段:主业务服务分别调用全部从业务的try操做,并在活动管理器中登记全部从业务服务。当全部从业务服务的try操做都调用成功或者某个从业务服务的try操做失败,进入第二阶段。第二阶段:活动管理器根据第一阶段的执行结果来执行confirm或cancel操做。若是第一阶段全部try操做都成功,则活动管理器调用全部从业务活动的confirm操做。不然调用全部从业务服务的cancel操做。与2PC比较:
缺点:
三、基于消息的分布式事务
核心思想:
eBay 的架构师Dan Pritchett,曾在一篇解释BASE 原理的论文《Base:An Acid Alternative》中提到一个eBay 分布式系统一致性问题的解决方案。它的核心思想是将须要分布式处理的任务经过消息或者日志的方式来异步执行,消息或日志能够存到本地文件、数据库或消息队列,再经过业务规则进行失败重试,它要求各服务的接口是幂等的。
基于消息的分布式事务模式核心思想是经过消息系统来通知其余事务参与方本身事务的执行状态。消息系统的引入更有效的将事务参与方解耦,各个参与方能够异步执行。
该种模式的难点在于解决本地事务执行和消息发送的一致性:二者要同时执行成功或者同时取消执行。
实现上主要有两种方式:
基于事务消息的方案
基于本地消息的方案
1)基于事务消息的分布式事务普通消息是没法解决本地事务执行和消息发送的一致性问题的。由于消息发送是一个网络通讯的过程,发送消息的过程就有可能出现发送失败、或者超时的状况。超时有可能发送成功了,有可能发送失败了,消息的发送方是没法肯定的,因此此时消息发送方不管是提交事务仍是回滚事务,都有可能不一致性出现。解决这个问题,须要引入事务消息,事务消息和普通消息的区别在于事务消息发送成功后,处于 prepared 状态,不能被订阅者消费,等到事务消息的状态更改成可消费状态后,下游订阅者才能够监听到次消息。本地事务和事务消息的发送的处理流程以下:
2)基于本地消息的分布式事务
基于事务消息的模式对 MQ 系统要求较高,并非全部 MQ 系统都支持事务消息的,RocketMQ 是目前为数很少的支持事务消息的 MQ 系统。若是所依赖的 MQ 系统不支持事务消息,那么能够采用本地消息的分布式模式。该种模式的核心思想是:上游服务:
下游服务:
基于消息的分布式事务能够将分布式系统之间更有效的解耦,各个事务参与方之间的调用再也不是同步调用。
对MQ系统的要求较高,对业务实现也有必定的侵入性,要么提供事务消息状态查询接口,要么须要维护本地消息表。而且原则上只接受下游分支事务的成功,不接受事务的回滚,若是失败就要一直重试,适用于对最终一致性敏感度较低的业务场景,例如跨企业的系统间的调用,适用的场景有限。
总结
阅读了很多这方面的文章,在此基础上,总结一下分布式事务一致性的解决方案。分布式系统的事务一致性自己就是一个技术难题,目前没有一种很简单很完美的方案可以应对全部场景。分布式系统的一个难点就是由于“网络通讯的不可靠”,只能经过“确认机制”、“重试机制”、“补偿机制”等各方面来解决问题。在综合考虑可用性、性能、实现复杂度等各方面的状况上,比较好的选择是“异步消息确保最终一致性”,只是具体实现方式上有一些差别。