前言

上一章我们了解了zookeeper到底是什么,这一章重点来看zookeeper当初到底面临什么问题?

而zookeeper又是如何解决这些问题的?

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

分布式事务

我们首先考虑一致性的特殊情况,即分布式事务的情况。分布式事务对于一致性的要求是强一致性,因此对于我们后续讨论有一定的借鉴意义。这里我们用到一个经典的例子:bob给smith转账,强一致性的要求一定是需要对外来说bob减钱的同时smith加钱。

单机环境下是这样的:

简单讲就是有关bob的减钱和smith的加钱都转同一个库来做,可以采用数据库的事务特性轻松支持。保证bob给smith转账的安全性。

而分布式环境就变这样了:

假设应用服务器是A,bob端的数据库是B,smith端的数据是C,那么A做成一个转账,需要B事务成功提交,并且C事务成功提交。然而因为网络的影响,可能出现两种情况

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

  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阶段的问题能够完全避免。

  1. 考虑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.超时。保守处理,超时可以当做失败。

  1. 考虑precommit阶段的响应。

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

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

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

  1. 考虑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;或者采用一些更加复杂的方式,比如将消息表与业务表放同库,利用数据库的事务来保证一致性,而消息系统只需要轮训该消息表即可;当然,也有消息的二阶段提交+补偿的方式。消息事务解决了消息发起方,即生产者与消息中间件之间的一致性问题。

try{  

    //数据库操作  

    //消息投递  

}catch(Exception e){  

    //回滚  

}

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

最后

我这边整理了一份:Zookeeper相关资料,Java核心知识点(包括Spring全家桶系列、面试专题和20年最新的互联网真题、电子书等)有需要的朋友可以关注公众号【程序媛小琬】即可获取。

什么是ZooKeeper?ZooKeeper分布式事务详解的更多相关文章

  1. Spring 分布式事务详解

    在学习分布式事务的过程中会遇到以下关键名词: 相关名词: XA :XA规范的目的是允许多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效.X ...

  2. Zookeeper系列二:分布式架构详解、分布式技术详解、分布式事务

    一.分布式架构详解 1.分布式发展历程 1.1 单点集中式 特点:App.DB.FileServer都部署在一台机器上.并且访问请求量较少 1.2  应用服务和数据服务拆分  特点:App.DB.Fi ...

  3. Zookeeper客户端Curator使用详解

    Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...

  4. 转:Zookeeper客户端Curator使用详解

    原文:https://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBo ...

  5. Hadoop生态圈-zookeeper的API用法详解

    Hadoop生态圈-zookeeper的API用法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.测试前准备 1>.开启集群 [yinzhengjie@s101 ~] ...

  6. spring事务详解(五)总结提高

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.概念 ...

  7. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  8. spring事务详解(一)初探事务

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...

  9. PHP mysql与mysqli事务详解

    官方对PHP连接到MySQL数据库服务器的三种主要的API简介如下: http://php.net/manual/zh/mysqli.overview.php PHP mysql与mysqli事务详解 ...

随机推荐

  1. linux下安装python3.7.1

    一.安装依赖环境 输入命令:yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readlin ...

  2. mq消息消费,broker选址

    PullRequest.MessageQueue.BrokerName 根据PullRequest.MessageQueue得到brokerId,默认0或者用缓存中的suggest,每次消息拉取后会更 ...

  3. 这些鲜为人知的前端冷知识,你都GET了吗?

    背景 最近公司项目不多,比较清闲,划水摸鱼混迹于各大技术博客平台,瞬间又GET了好多前端技能,一些属于技巧,一些则是闻所未闻的冷知识,一时间还消化不过来,不由的发出一声感叹! 前端可真是博大精深 于是 ...

  4. BYTE WORD DWORD

    在Visual C++ 6.0中,BYTE与WORD,DWORD本质上都是一种无符号整型,它们在WINDEF.H中被定义,定义如下:typedef unsigned char       BYTE;t ...

  5. 小米ICPC第一场自闭记

    这次终于找到了靠谱队友,比之前我做不出来==队友做不出来好太多了 昨天3人热身赛疯狂杀了8道题,感觉今天稳了 一开始就瞅了A题,发现似乎可以dp,看了看数据,1e7,大概想出了nsqrtn算法,想着肯 ...

  6. 洛谷P3906 Hoof Paper, Scissor (记忆化搜索)

    这道题问的是石头剪刀布的的出题问题 首先不难看出这是个dp题 其次这道题的状态也很好确定,之前输赢与之后无关,确定三个状态:当前位置,当前手势,当前剩余次数,所以对于剪刀,要么出石头+1分用一次机会, ...

  7. PyQt(Python+Qt)学习随笔:QMdiArea多文档界面部件的subWindowActivated信号

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 QMdiArea的subWindowActivated在一个窗口激活( ...

  8. PyQt学习随笔:自定义Qt事件可以使用的事件类型的常量值范围

    除了<PyQt学习随笔:Qt事件QEvent.type类型常量及其含义资料速查>介绍的Qt已经定义的事件外,Qt还支持自定义事件. 为了方便起见,可以使用 registerEventTyp ...

  9. PyQt(Python+Qt)学习随笔:Qt Designer中主窗口对象dockNestingEnabled属性

    dockNestingEnabled 属性是确认主窗口的浮动部件(dock widget)是否允许嵌套的一个属性. 如果此属性为False,则浮动部件停靠区域只能包含一个浮动部件(水平或垂直).如果此 ...

  10. tesseract-ocr 图片文字识别

    本篇记录下python识别图片中的文字 所需的安装配置:  安装库: pip install pytesseract pip install PILLOW   安装 Tesseract-OCR软件: ...