【简记】Operating System—— distributed coordination(2PC 3PC)

This memo is based on the course of Dr.Li with Operating System as the reference book.

研究如何把集中式同步机制扩展到分布式环境中,以及在分布式系统中处理死锁的方法。

本章内容:

  • 事件排序
  • 利用时间戳实现互斥
  • 利用锁实现互斥
  • 分布式事务实现原子性(2PC,3PC)

18.1 事件排序

在分布式系统中,由于没有公共的存储器,也没有公共的时钟,
因此,有时不能判断两件事件谁先发生。

在此提出一种分布式算法来将事前关系扩充为系统中的所有事件的一致性整体排序。

这里写图片描述
如果事件A和B 不是" → "关系,则称这两个事件是井发执行的。此时,无论哪个事件都不能以因果关系影响另一个。

===
18.1.2 实现

将每个系统事件与一个时间戳( time stamp )相关联,然后可以定义全局排序(global ordering ) 的必要条件:对每一对事件A 和B,如果A→B ,则A的时间戳小于B的时间戳。

每个进程有一个逻辑时钟,如果在该进程中A在B之前执行,则A的时间戳小于B。
跨进程通信时,当P2的B收到来自P1的A的信息,而此时B的时间戳可能小于A(P2的处理器比P1的慢),则更新B的时间戳为A的加1。

最后建立规则:如果两个时间的时间戳相同,则是并发的。


18.2 互斥

18.2.2 完全分布式的算法
这里写图片描述

此协议特别适合于小的、稳定的协作进程集合。

18.2.3 令牌传递算法

令牌( token ) 是在系统中传递的一种特殊的消息,只有令牌的持有者才有权进入临界区。由于只有一个令牌,因此一次只有一个进程能进入临界区。

假定系统中的进程被逻辑地组织成一个环结构。


18.3 事务

事务的ACID

事务是保证数据库从一个一致性的状态永久地变成另外一个一致性状态的根本,其中,ACID是事务的基本特性。

A是Atomicity,原子性。一个事务往往涉及到许多的子操作,原子性则保证这些子操作要么都做,要么都不做,而不至于出现事务的部分操作成功,而另外一部分操作没有成功。如果事务在执行的过程中发生错误,那么数据库将回滚到事务发生之前的状态。比如银行的转账服务。

这个事务的最终结果一定是某个账户的余额增加了x,而另外一个账户的余额减少了x,或者两个账户的余额未发生变化。而不会出现其他情况。

C是Consistency,一致性。一致性是指事务发生前和发生以后,都不会破坏数据库的约束关系,保证了数据库元素的正确性、有效性和完整性。这种约束关系可以是数据库内部的约束,比如数据库元素的值必须在一定的范围内,也可以是应用带来的约束,比如转账以后银行账户的余额不能为负数。

I是Isolation,隔离性。一个事务的操作在未提交以前,是不会被并行发生的其他事务访问到的。也就是说,数据库操作不会看到某个事务的中间操作结果,比如转账过程中,用户是不能查询到一个账户余额减少了,而另外一个账户余额未发生变化的情况。

D是Durability,持久性。事务完成以后,它对数据库的影响是永久性的,即使在数据库系统发生宕机或者其他故障的情况下,这种影响也会得到保持。

===

分布式系统中是怎么保证这4个特性的呢?我们先来看看原子性的实现二阶段提交协议(2PC)。

二阶段提交(2PC)

分布式系统的一个难点是如何保证架构下多个节点在进行事务性操作的时候保持一致性。为实现这个目的,二阶段提交算法的成立基于以下假设:

1)该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts)。且节点之间可以进行网络通信。
2)所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失。
3)所有节点不会永久性损坏,即使损坏后仍然可以恢复。

第一阶段(投票阶段):

1)协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。

2)参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)

3)各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。

第二阶段(提交执行阶段):

当协调者节点从所有参与者节点获得的相应消息都为"同意"时:

1)协调者节点向所有参与者节点发出"正式提交(commit)"的请求。

2)参与者节点正式完成操作,并释放在整个事务期间内占用的资源。

3)参与者节点向协调者节点发送"完成"消息。

4)协调者节点受到所有参与者节点反馈的"完成"消息后,完成事务。

如果任一参与者节点在第一阶段返回的响应消息为"中止",或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

1)协调者节点向所有参与者节点发出"回滚操作(rollback)"的请求。

2)参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。

3)参与者节点向协调者节点发送"回滚完成"消息。

4)协调者节点受到所有参与者节点反馈的"回滚完成"消息后,取消事务。

不管最后结果如何,第二阶段都会结束当前事务。

二阶段提交看起来确实能够提供原子性的操作,但是不幸的事,二阶段提交还是有几个缺点的

1、执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。

2、参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。(没有多少容错机制)

3、单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)

4、二阶段无法解决的问题:协调者在发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
  
  5、数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。

===
2 三阶段提交协议(3PC)

与两阶段提交不同的是,三阶段提交有两个改动点。

1、引入超时机制。同时在协调者和参与者中都引入超时机制。

2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

具体流程见下图:

这里写图片描述
CanCommit阶段

3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

1.事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。

2.响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No

PreCommit阶段

协调者根据参与者的反应情况来决定是否可以继续事务的PreCommit操作。根据响应情况,有以下两种可能。

假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。

1.发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。

2.事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。

3.响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。

1.发送中断请求 协调者向所有参与者发送abort请求。

2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

doCommit阶段

该阶段进行真正的事务提交,也可以分为以下两种情况。

执行提交

1.发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。

2.事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。

3.响应反馈 事务提交完之后,向协调者发送Ack响应。

4.完成事务 协调者接收到所有参与者的ack响应之后,完成事务。

中断事务 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

1.发送中断请求 协调者向所有参与者发送abort请求

2.事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。

3.反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息

4.中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。

在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,继续进行事务的提交。(其实这个应该是基于概率来决定的,当进入第三阶段时,说明参与者在第二阶段已经收到了PreCommit请求,那么协调者产生PreCommit请求的前提条件是他在第二阶段开始之前,收到所有参与者的CanCommit响应都是Yes。(一旦参与者收到了PreCommit,意味他知道大家其实都同意修改了)所以,一句话概括就是,当进入第三阶段时,由于网络超时等原因,虽然参与者没有收到commit或者abort响应,但是他有理由相信:成功提交的几率很大。 )


两阶段提交与三阶段提交的区别:

三阶段提交也不完美。但是它比两阶段好。
两阶段的问题可以这样分解:

1,协调者出错,参与者也出错;

2,协调者出错,参与者不出错;

3,协调者不出错,参与者出错;

4,协调者不出错,参与者也不出错。

显然第4种不是问题。所以实际上只有3个问题。而问题2可以通过简单地NEW一个新的协调者来解决。问题3的错则显然正是两阶段提交协议的解决目标,所以也没有问题。有问题的只有协调者出错,参与者也出错的问题1。

这种情况可以被进一步分为参与者有没有收到提交的消息。如果参与者没有收到提交的消息,那么显然将不会(或没有—从系统恢复的角度)发生任何真正的提交行为;而如果有任何参与者收到了提交的消息,那么就很可能发生或已经发生了真正的提交行为。这个“可能”,为系统引入了不确定因素。系统没有办法解决这样的问题,唯一的办法便是引入超时机制。否则除了事务没有办法终结以外,部分参与者节点还有可能永不释放其所持有的全部数据锁。

超时机制的引入意味着将两阶段的第二阶段再度分开成两个阶段:不确定阶段与确定阶段。超时以前是不确定操作阶段,超时以后是确定操作阶段。因为在超时发生以前,系统处于不确定阶段,但是超时发生以后,系统则转入确定阶段。超时事件本身,则是系统进行状态转换的信号。但是因为真正引起超时的错只会在协调者与参与者同时出错(对于不出错但超时的情况,视为出错。即超时本身就是一种错)的情况下才会发生,在其它所有的情况下并不会发生,所以必须对这些情况进行相同的状态划分:准备好与提交状态。这些名词并不是很合乎它要表示的语义,但两个状态足够表达所有的情况才是最重要的事情。


所以3pc的优点就是引入了参与者侧的超时机制,在三个阶段中,任意阶段出现了超时情况,都可以继续执行下去

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值