前言:
这两天在尝试着看关于分布式系统中的常用协议和框架的文档,比较感兴趣的是分布式事务, 我常常会想一个场景,小明给小红汇钱的时候,如果中间悲催的出现xx问题怎么办?
我们知道可以用事务解决 ! 往往较大型网站及应用都是分布式部署的,数据库层面会拆解分库都不同的mysql服务器上。 这个时候就要上分布式事务了。 趁着热乎劲说下两阶段提交2pc的原理及实现。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。
那么什么是分布式事务—两阶段提交协议 ?
两阶段提交协议(Two-phase Commit,2PC)经常被用来实现分布式事务。一般分为协调器和若干事务执行者两种角色,这里的事务执行者就是具体的数据库,抽象点可以说是可以控制给数据库的程序。 协调器可以和事务执行器在一台机器上。
在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)。
我们设想从支付宝里转10000元到余额宝的场景… …
1) 首先我们的应用程序发起一个请求到协调器, 然后由控制器来保证分布式事务。
2) 准备凭证阶段
1. 协调器先将<prepare>消息写到本地日志。
2. 向所有的参与者发起<prepare>消息。以支付宝转账到余额宝为例,协调器给A的prepare消息是通知支付宝数据库相应账目扣款10000,协调器给B的prepare消息是通知余额宝数据库相应账目增加10000。
注:
为什么在执行任务前需要先写本地日志,主要是为了故障后恢复用,本地日志起到现实生活中凭证 的效果,如果没有本地日志(凭证),出问题容易死无对证;
参与者收到<prepare>消息后,执行具体本机事务,但不会进行commit,如果成功返回<yes>,不成功返回<no>。同理,返回前都应把要返回的消息写到日志里,当作凭证。
支付宝:
#author: rfyiamcool@163.com BEGIN WORK select money from zhifubao where user='xiaorui' for update; update zhifubao set money=money-10000 where user='xiaorui'; ... Operation N 向协调者发送YES或者NO ! 等待协调者的指令过来 !
余额宝:
#blog: xiaorui.cc BEGIN WORK select money from yuebao where user='xiaorui' for update; update yuebao set money=money+10000 where user='xiaorui'; ... Operation N 根据状态向协调者发送YES或者NO ! 然后等待协调者的指令过来 ... ....
4) 协调器收集所有执行器返回的消息,如果所有执行器都返回yes,那么给所有执行器发生送commit消息,执行器收到commit后执行本地事务的commit操作;如果有任一个执行器返回no,那么给所有执行器发送abort消息,执行器收到abort消息后执行事务abort操作。
#blog: xiaorui.cc if 协调者指令 == "to_commit": commit work #提交事务 else: ROLLBACK #回滚
注:
协调器或参与者把发送或接收到的消息先写到日志里,主要是为了故障后恢复用。举个例子,比如某个参与者从故障中恢复后,先检查本机的日志,如果已收到<commit >,则提交,如果<abort >则回滚。如果是<yes>,则再向控制器询问一下,确定下一步。如果什么都没有,则很可能在<prepare>阶段Si就崩溃了,因此需要回滚。
二阶段提交协议虽然相对简单,但他的性能不咋地,根本不适合高并发的系统。为什么?
1)两阶段提交涉及多次节点间的网络通信,通信时间太长!
2)事务时间相对于变长了,锁定的资源的时间也变长了,造成资源等待时间也增加好多!
正是由于分布式事务存在很严重的性能问题,大部分高并发服务都在避免使用,往往通过其他途径来解决数据一致性问题。
现在很多处理流程(Workflow)都会借鉴2PC这个算法,所以还是有学习的场景的。 下面我们再总结下二阶段提交的流程。
上图是正常的场景 ! 只要参与值返回yes,协调者就会发送commit提交指令。
下图是出错的场景,不管是网络异常中断,对端服务超时或异常,这对于分布式事务来说都是一次失败的任务,会触发abort中断,回滚事务。
参考链接:
http://blog.jobbole.com/89140/
广告在哪里。。。。。。。
哎, 能不能别这么气人…. 你是不是开AdBlock过滤广告了 …