前言:

    这两天在尝试着看关于分布式系统中的常用协议和框架的文档,比较感兴趣的是分布式事务, 我常常会想一个场景,小明给小红汇钱的时候,如果中间悲催的出现xx问题怎么办?


我们知道可以用事务解决 ! 往往较大型网站及应用都是分布式部署的,数据库层面会拆解分库都不同的mysql服务器上。  这个时候就要上分布式事务了。 趁着热乎劲说下两阶段提交2pc的原理及实现。 

该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。

http://xiaorui.cc/2016/02/25/%E7%90%86%E8%A7%A3%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%9A%84%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A42pc/

那么什么是分布式事务—两阶段提交协议 ? 

两阶段提交协议(Two-phase Commit,2PC)经常被用来实现分布式事务。一般分为协调器和若干事务执行者两种角色,这里的事务执行者就是具体的数据库,抽象点可以说是可以控制给数据库的程序。 协调器可以和事务执行器在一台机器上。

在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)。


我们设想从支付宝里转10000元到余额宝的场景… … 

1) 首先我们的应用程序发起一个请求到协调器, 然后由控制器来保证分布式事务。

2) 准备凭证阶段 

1. 协调器先将<prepare>消息写到本地日志

2. 向所有的参与者发起<prepare>消息。以支付宝转账到余额宝为例,协调器给A的prepare消息是通知支付宝数据库相应账目扣款10000,协调器给B的prepare消息是通知余额宝数据库相应账目增加10000。

注:
为什么在执行任务前需要先写本地日志,主要是为了故障后恢复用,本地日志起到现实生活中凭证 的效果,如果没有本地日志(凭证),出问题容易死无对证;

参与者收到<prepare>消息后,执行具体本机事务,但不会进行commit,如果成功返回<yes>,不成功返回<no>。同理,返回前都应把要返回的消息写到日志里,当作凭证。

支付宝:


余额宝:

4) 协调器收集所有执行器返回的消息,如果所有执行器都返回yes,那么给所有执行器发生送commit消息,执行器收到commit后执行本地事务的commit操作;如果有任一个执行器返回no,那么给所有执行器发送abort消息,执行器收到abort消息后执行事务abort操作。


注:

     协调器或参与者把发送或接收到的消息先写到日志里,主要是为了故障后恢复用。举个例子,比如某个参与者从故障中恢复后,先检查本机的日志,如果已收到<commit >,则提交,如果<abort >则回滚。如果是<yes>,则再向控制器询问一下,确定下一步。如果什么都没有,则很可能在<prepare>阶段Si就崩溃了,因此需要回滚。

二阶段提交协议虽然相对简单,但他的性能不咋地,根本不适合高并发的系统。为什么?

1)两阶段提交涉及多次节点间的网络通信,通信时间太长!
2)事务时间相对于变长了,锁定的资源的时间也变长了,造成资源等待时间也增加好多!
正是由于分布式事务存在很严重的性能问题,大部分高并发服务都在避免使用,往往通过其他途径来解决数据一致性问题。

现在很多处理流程(Workflow)都会借鉴2PC这个算法,所以还是有学习的场景的。  下面我们再总结下二阶段提交的流程。

上图是正常的场景 ! 只要参与值返回yes,协调者就会发送commit提交指令。 

下图是出错的场景,不管是网络异常中断,对端服务超时或异常,这对于分布式事务来说都是一次失败的任务,会触发abort中断,回滚事务。



参考链接:

http://blog.jobbole.com/89140/



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品

2则回应给“理解分布式事务的两阶段提交2pc”

  1. 广告not found说道:

    广告在哪里。。。。。。。

发表评论