当前位置: 首页 > 编程日记 > 正文

zookeeper入门系列 : 分布式事务

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

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

分布式事务

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

单机环境下是这样的

简单讲就是有关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阶段的问题能够完全避免。

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

try{ //数据库操作 //消息投递 
}catch(Exception e){  //回滚 
}

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

参考

  • 分布式开放消息系统(RocketMQ)的原理与实践
  • 消息中间件(一)分布式系统事务一致性解决方案大对比,谁最好使?
  • 最终一致性

转载于:https://www.cnblogs.com/haihua85/p/8711215.html

相关文章:

rdlc报表显示条码 .

1.条码的生成: private Bitmap GetCode39(string strSource) { int x 5; //左邊界 int y 0; //上邊界 int WidLength 2; //粗BarCode長度 int NarrowLength 1; //細BarCode長度 …

python列表(数组)

python列表(数组) 列表(list) 就是 数组 - 列表是Python中的一个对象 - 对象(object)就是内存中专门用来存储数据的一块区域 - 之前我们学习的对象,像数值,它只能保存一…

【js】common.jsp的使用

通过将引入common.jsp将所有文件都需要的内容或静态资源引入&#xff0c;相当于一个页面&#xff0c;在页面被编译之前合并。 代码实现 <% include file "common.jsp的相对路径"%> 注意&#xff1a; <% page language"java" contentType&quo…

12th,Jan 研究生创新项目申报成功

今天的好消息是研究生创新项目申报成了&#xff0c;省里拨下来是1.8k&#xff0c;本来学校应该配3.6k&#xff0c;但是按照以往的经验&#xff0c;学校那3.6k是不会给的。。。所以总共就1.8k&#xff0c;呵呵&#xff0c;钱虽然不多&#xff0c;但是也是个小小小的成就吧。 昨晚…

Android studio中2种build.gradle文件介绍

根目录下的build.gradle通常不需要修改这个文件中的内容&#xff0c;除非需要添加一些全局的项目构建配置 buildscript {repositories {google() //声明代码托管仓库Googlejcenter() //声明代码托管仓库&#xff0c;用于引用jcenter上的开源项目}dependencies {classpath …

10个有趣的javascript和css库(2019年5月最新)

我们的使命是让您了解最新和最酷的Web开发趋势。这就是为什么我们每个月都会发布一些精选的资源&#xff0c;这些资源是我们偶然发现并认为值得您关注的。 1.Tessaract.js 强大的javascript&#xff08;节点和浏览器&#xff09;库&#xff0c;用于从图像中提取文本。它能自动检…

快速开发rails、==常用插件==

1、简化css编写的&#xff1a;sass http://sass-lang.com/download.html 2、简化html编写的:haml http://haml-lang.com/转载于:https://www.cnblogs.com/klobohyz/archive/2011/10/31/2230080.html

【js】绑定事件的两种方法

方法一&#xff1a; 为需要绑定事件的标签添加一个属性onclick 代码实现&#xff1a; <input type"button" value"测试按钮" onclick"testClick()" /> 方法二&#xff1a; 用jquery方法绑定事件 代码实现&#xff1a; <input id&…

对于学习方式的一些思考

再牛X的书都不要太当回事儿&#xff0c;书只是知识的一个载体&#xff0c;掌握知识的途径之一。学习的过程应该是由一个个知识模块所驱动的&#xff0c;继而去调动身边的学习资源和工具&#xff0c;而不是被一本本所谓的牛书生拉硬拽着去学一大套可能永远都用不到的东西。“知识…

python开发环境安装

PyCharm的安装地址&#xff1a;http://www.jetbrains.com/pycharm/download/#sectionwindows&#xff0c;免费的可以选择社区版本 Python解释器的安装地址&#xff1a;https://www.python.org/downloads/&#xff0c;选择对应的平台及版本下载&#xff0c;安装时勾选 添加到环…

HGOI 20190709 题解

Problem A 紫色激情 一个序列$\{a_n\}$&#xff0c;求出方差最大的子序列。 其中方差 [l,r] 的定义是$S^2 \frac{1}{n} \sum\limits_{il}^{r} (x_i-\bar{x})^2$ 对于100%的数据满足$n \leq 10^3$ Sol : 直接推一波公式就可以前缀和优化了。 ${ S_{l,r} }^2 -\bar{x}^2 \frac{…

C++标准库简介(转)

C标准库的所有头文件都没有扩展名。C标准库的内容总共在50个标准头文件中定义&#xff0c;其中18个提供了C库的功能。 <cname>形式的标准头文件【 <complex>例外】其内容与ISO标准C包含的name.h头文件相同&#xff0c;但容纳了C扩展的功能。在 <cname>形式标…

【jquery】$.each的使用方法

代码实现&#xff1a; $.each(goodsArray, function(index){if(goods.barCode goodsArray[index].barCode){goodsArray[index].count;boo true;return; }});

MyEclipse插件安装

一、安装方法&#xff1a; 方法一、如果可以上网可在线安装 1. 打开Myeclipse&#xff0c;在菜单栏中选择Help→Software Updates→Find and Install; 2. 选择Search for new features to install&#xff0c;点击Next进入下一步; 3. 点击"New Remote Site"按钮&…

软件质量与测试 第4周小组作业

一、项目地址 https://github.com/changjiang666/WcPro 二、PSP 三、设计思路 我负责main函数的编写和print输出模块的编写。 1.main函数 int main(/*int argc, char **argv*/) {char *textBuf readfile("test.txt"); // 读取输入文件WcPro wcpro(textBuf);// 将输入…

UVA 10714 - Ants

这道题是要我们找出所有蚂蚁中最靠近端点和最靠近中间的蚂蚁所在的位置&#xff0c;计算端点的蚂蚁爬到另一个 端点的时间和计算靠近中间的蚂蚁爬到离他近的端点的时间。我们只需分输入的位置在棒的左边还是右边 来讨论就行。 #include<iostream>using namespace std;int…

Mysql Cluster 集群 windows版本

VM1&#xff1a;192.168.220.102 管理节点(MGM) VM2&#xff1a;192.168.220.103 数据节点(NDBD1)&#xff0c;SQL节点(SQL1) VM3&#xff1a;192.168.220.104 数据节点(NDBD2)&#xff0c;SQL节点(SQL2) MySQL Cluster版本&#xff1a;7.4.6 (MSI Installer) 下载地址&…

【js】通过js代码改变html表单中的数据

代码实现&#xff1a; document.getElementById("sum").innerHTML sum;

Asp.net MVC 3实例学习之ExtShop(五)——产品详细页

在产品详细页需要使用到tab控件&#xff0c;在jquery的ui包已包含改控件&#xff0c;因而将相应文件链接加到母版页就可以了。 打开“ProductController”文件&#xff0c;在里面添加一个Details操作&#xff0c;代码如下&#xff1a; 1 public ActionResu…

linux安装配置postgres及使用dblink

好久不写东西&#xff0c;一直在看些开源的东西&#xff0c;下面贴下linux上安装配置postgres及使用dblink的操作参考&#xff0c;以供读者和自己今后参考&#xff1a; 1、下载源码&#xff1a;postgresql-9.3.2.tar.gz 2、创建postgres cluster组和用户&#xff1a; groupadd …

从瀑布模型、极限编程到敏捷开发

从瀑布模型、极限编程到敏捷开发---软件开发管理者思维的变化Jack zhai软件开发是一种对人类智慧的管理&#xff0c;对人大脑思维的“工厂化”管理。人是有感情的、有情绪的、变化的、相对独立的工作单元&#xff0c;这与冰冷的机器是不可比的&#xff0c;所以在中国的历史上&a…

递归和循环:跳台阶和变态跳台阶和矩形覆盖

题目描述 跳台阶:一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法&#xff08;先后次序不同算不同的结果&#xff09;。变态跳台阶:一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级……它也可以跳上n级。求该青蛙跳上…

【js】将json类型的数组或对象转为字符串

代码实现&#xff1a; JSON.stringify(goodsList); 注&#xff1a;该用法多用于数据的传输&#xff0c;如页面于servlet的数据传输不能使用gson的数组直接传输&#xff0c;使用该方法便可解决问题。

Android XML pull 解析器

Android 并未提供对 Java StAX API 的支持。但是&#xff0c;Android 确实附带了一个 pull 解析器&#xff0c;其工作方式类似于 StAX。它允许您的应用程序代码从解析器中获取事件&#xff0c;这与 SAX 解析器自动将事件推入处理程序相反。清单 10 显示了提要解析接口的一个 pu…

Zepto.js库touch模块代码解析

Zepto.js也许并不陌生&#xff0c;专门针对移动端开发&#xff0c;Zepto有一些基本的触摸事件可以用来做触摸屏交互&#xff08;tap事件、swipe事件&#xff09;&#xff0c;Zepto是不支持IE浏览器的。 下面来解析一些Zepto.js触摸事件的解析&#xff1a; 1.触摸事件离不开:tou…

PHP 常用字符串处理代码片段

移除 HTML 标签 $text strip_tags($input, ""); 返回 $start 和 $end 之间的文本function GetBetween($content,$start,$end){ $r explode($start, $content); if (isset($r[1])){ $r explode($end, $r[1]); return $r[0]; } ret…

【maven】初识maven

一&#xff1a;maven的配置&#xff1a; 集成到eclipse步骤&#xff1a; 1、下载maven&#xff0c;放到软件安装目录&#xff0c;打开目录&#xff1a;MAVEN_HOME/conf/ 2、修改文件setting.xml&#xff1a;仓库配置目录&#xff1a;<localRepository>D:\DATA\lo…

[C++再学习系列] 函数模板和类模板

函数模板和类模板 C 提供类模板和函数模板。函数模板允许重载 &#xff0c;而类模板不允许重载(类无重载概念)。类模板可以进行全特化和偏特化&#xff0c;而函数模板仅能够全特化 。因此&#xff0c;写一个看似函数模板偏特化的函数模板实际上是在写一个单独的主函数模板&…

git init 与 git init --bare 区别

git init 与 git init --bare 区别 发现问题 最早是在公司的wiki上发现了这个命令&#xff0c;google后发现值得记录下来 实践中发现的区别 网上找了很多资料&#xff0c;但说的很乱&#xff0c;干脆在自己的服务器上执行对比了一下&#xff1a;git init demo1 # 表示创建一个…

一个虚函数和虚继承的问题。

这个问题困惑好几天了。废话不多说&#xff0c;先上代码。 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 virtual void aa() 8 { 9 } 10 private: 11 char k[3]; 12 }; 13 14 class B:publi…