zookeeper入门系列-理论基础-分布式事务

转自https://blog.csdn.net/liweisnake/article/details/68942165数据库

 

上一章咱们了解了zookeeper究竟是什么,这一章重点来看zookeeper当初到底面临什么问题?而zookeeper又是如何解决这些问题的?安全

实际上zookeeper主要就是解决分布式环境下的一致性问题。那么解决这个问题到底有哪些难点呢?咱们一步一步来阐述和推理这个过程。服务器

 

分布式事务网络

咱们首先考虑一致性的特殊状况,即分布式事务的状况。分布式事务对于一致性的要求是强一致性,所以对于咱们后续讨论有必定的借鉴意义。这里咱们用到一个经典的例子:bob给smith转帐,强一致性的要求必定是须要对外来讲bob减钱的同时smith加钱。见文献1(图片也来源于文献1)app

单机环境下是这样的框架

简单讲就是有关bob的减钱和smith的加钱都转同一个库来作,能够采用数据库的事务特性轻松支持。保证bob给smith转帐的安全性。分布式

 

而分布式环境就变这样了性能

假设应用服务器是A,bob端的数据库是B,smith端的数据是C,那么A作成一个转帐,须要B事务成功提交,而且C事务成功提交。然而由于网络的影响,可能出现两种状况spa

1. 若是bob扣款成功,而网络通知smith失败了,则会出现bob的钱减了,smith的钱没加.net

2. 若是bob扣款不成功,而smith加钱成功了,则会出现smith钱增长了,可是bob的钱也没减小

 

2PC

这种不一致的问题困扰着你们。任意一边出错想要回滚另外一边都不是简单的数据库回滚的事情( 由于此时已经成功提交),而是须要作业务的逆向操做,而不一样业务的逆操做都不一样,致使复杂性增长。考虑数据库事务的执行其实是先将执行操做写入binlog,等到最后经过一个commit指令将binlog的内容一次更新到表中,或者写到一半经过一个rollback指令将binlog中的内容回滚。因而乎,能够想到使用2个阶段来执行这个过程,第一阶段,写入binlog;第二阶段执行commit或者rollback。这就是著名的两阶段提交协议(2PC)。若是仔细考虑,会发现两阶段协议并无解决问题,只不过下降了出错的几率而已,由于第二阶段一样存在上面的两种状况。注意最终状态是多台机器的状态&&的 结果。如下是两阶段协议的时序图:

1. 考虑prepare阶段的响应(由于请求阶段和执行阶段均可以在最后响应中体现出来),对于分布式环境中,任意时刻考虑3种状态:成功、失败、超时。

a.成功。没必要处理,执行后续行为commit。

b.失败。这是执行阶段出错,执行后续行为rollback。

c.超时。这多是执行阶段太慢,也多是网络阶段太慢或丢包,可是保守处理,超时能够当作出错。

能够看出,prepare阶段的问题可以彻底避免。

2. 考虑commit阶段,一样考虑成功失败超时3种状态。

a. 成功。整个事务成功执行

b. 失败。提交出错,假设此时前面的B已经提交成功了,则一样面临须要回滚B却没法回滚的问题,由于B已经提交成功了。

c. 超时。同上。

还有一种例外状况,即prepare阶段完成后A挂了,则B,C即进入不知所措的状态。

能够看出,在2PC中事务没法作到像单机同样安全,只不过下降了出问题的几率。

 

3PC

针对如何解决2PC中的例外状况,出现了3阶段提交协议。3阶段的主要改进是把2阶段的prepare再分为canCommit和preCommit两个阶段。

 

1. 考虑cancommit阶段的响应。

a.成功。没必要处理,执行后续行为precommit。

b.失败。说明没法执行,无须后续提交或回滚行为。

c.超时。保守处理,超时能够当作失败。

2. 考虑precommit阶段的响应。

a.成功。没必要处理,执行后续行为docommit。

b.失败。执行阶段出错,执行后续行为rollback。

        c.超时。执行阶段太慢,也多是网络阶段太慢或丢包,可是保守处理,超时能够当作出错。

3. 考虑cancommit阶段的响应。

a.成功。整个事务成功执行。

b.失败。提交出错,假设此时前面的B已经提交成功了,则一样面临没法回滚的问题。

c.超时。保守处理,超时能够当作失败。

例外状况,即自cancommit返回成功后的任意阶段A挂掉了,那么BC一样可以知道这个事务正在发生(由于cancommit已经提交了足够信息让BC知晓此事),因而BC能够在无A的状况下继续执行后续的阶段(好比BC投票启动新的A',并提供A'足够信息)。因而3PC正好解决了2PC的例外状况。

可是3PC仍然存在相似2PC的问题,即最后阶段失败或超时一样有可能出现数据不一致的问题。因此3PC仍然只是下降了发生几率,并无真正解决问题。

 

XTS

工业界的对分布式事务的应用是如何呢?能够参考某宝的知名分布式框架XTS。

XTS本质上是2PC(实际上若是引入3PC会多2n次网络交互,在量大时反而更加不安全)。XTS引入协调者A的server部分,其实是一个大集群,以配置的方式接入各类须要分布式事务的业务,集群由专门的团队维护,保证其可用性和性能;而协调者A的client部分则经过发起方调用,prepare阶段时,先经过client将本次事务信息发送到server,落库,而后即时推送prepare请求到B和C,当收到B,C的响应时把他们状态入库,若是正常,则作commit提交;不然会用定时任务去推送未完成的状态直到完成。上文提到的prepare以后协调者A挂了这种状况,在server集群的保证下,几乎不多会发生。而上文提到的全部超时的状况,均可以经过定时任务推送拿到一个肯定的状态而不是盲目的选择回滚或者提交。另外因为B和C都是集群,不多会发生屡次请求过去无响应的状况。直到最后一种状况就是commit时B成功了C失败了,或者反过来B失败C成功,这种状况成为悬挂事务,最终等待人工来解决,听说天天都有几笔到几十笔。

无疑XTS做为2PC在工业界的应用,是至关了不得的设计,经过各类方式规避了各类可能的不一致性,在性能,效率等方面作到了平衡。

 

TCC(Try/Confirm/Cancel)

业务补偿类型,其基本思想是对每个业务操做作一个逆操做,一旦成功了,就作正向业务,一旦失败了就作业务的逆操做。一般在业务逻辑简单而且正逆操做清晰的时候用比较好。

 

查询补偿

典型的场景是向银行发送了转帐请求未获得明确的成功失败返回码,此时先作业务结果的查询,根据结果作相应处理,好比查询结果成功,则置状态为成功,查询结果失败,则作相应的业务补偿,查询结果为未知,则继续查询。

 

消息事务及消息重试

事务消息及消息重试本质上都是将一些通用的事务交给消息中间件,经过消息中间件来保证消息的最终一致性。

事实上,消息事务解决了这类问题,即本地事务和消息应当有一致性,解决这个一致性比较麻烦,好比消息中间件和业务同时实现XA;或者采用一些更加复杂的方式,好比将消息表与业务表放同库,利用数据库的事务来保证一致性,而消息系统只须要轮训该消息表便可;固然,也有消息的二阶段提交+补偿的方式。消息事务解决了消息发起方,即生产者与消息中间件之间的一致性问题。

 

[plain] view plain copy

  1. try{  
  2.     //数据库操做  
  3.     //消息投递  
  4. }catch(Exception e){  
  5.     //回滚  
  6. }  

消息中间件与消费者之间的一致性问题则须要经过重试+幂等来解决。消息重试中主要考虑重试次数以及重试时间的阈值变化。


 

 

分布式开放消息系统(RocketMQ)的原理与实践 http://www.jianshu.com/p/453c6e7ff81c

消息中间件(一)分布式系统事务一致性解决方案大对比,谁最好使? http://blog.csdn.net/lovesomnus/article/details/51785108

最终一致性 https://zhuanlan.zhihu.com/p/25933039

相关文章
相关标签/搜索