Atomicity All-or-Nothing and Before-or-After——MIT6.824

Atomicity: All-or-Nothing and Before-or-After——MIT6.824

《Principles Computer System Design Introduction》

Before-or-After Atomicity: Coordinating Concurrent Threads

并发操作中经常会出现data race condition,从程序员的角度看,有两种不同的并发协调做法:序列协调和原子性(sequence coordina­tion and before-or-after atomicity)。序列协调指的是约束"动作W必须在动作X之前发生",而原子性则是一种更普遍的约束,即同时对同一个数据进行操作的若干动作不会相互干扰。我们对Before-or-after atomicity的定义是:

Concurrent actions have the before-or-after property if their effect from the point of view of their invokers is the same as if the actions occurred either completely before or completely after one another.

与序列协调不同,before-or-after原子性对于程序员来说无法知道共享变量的所有其他动作的ID。程序员需要的是一种自动的隐式机制,可确保正确处理每个共享变量。举个例子,在操作系统中,几个并发线程可能决定在某个时间使用共享打印机。而且,哪个线程首先使用打印机并不重要,重要的是是打印机的一次使用在下一次开始之前必须要完成。

否则,多个线程交叉发生很可能引起最终的结果不一致,如图,如果两个线程对这个操作交叉执行,就会产生不一致的行为,原子性要保证的就是两个线程对B的操作必须是原子操作。

img

Correctness and Serialization

我们的目标是对before-or-after原子性进行正确性的验证,而不会涉及使用该机制的应用程序是否正确的问题。此正确性标准意味着如果并发操作的结果是通过某些纯串行应用的相同操作获得的结果,则算正确协调并发操作。

因此我们对before-or-after原子性的定义就是每个before-or-after的行为都表现得是执行之前或者完全执行之后的效果。

Simple Locking

simple locking有两个规则,首先是每个事务必须在执行任何实际读取和写入之前为其操作的所有共享对象获取锁;其次是必须事务完成上次更新并提交或者重新加载数据并终止后才会释放锁。

simple locking能有效地协调并发事务,在该规则下一个事务必须在前一个事务完成之后进行、在后一个事务开始之前进行,并且进行中的事务不会拥有共同的数据。并发事务产生的结果就像是按照序列化顺序进行的一样。

但是simple locking也会因为性能问题影响其并发过程,因为它要求事务获取它将要读取或写入的每个共享对象的锁,如果其需要读取的锁数量大于当前的数量,那么就会在一定程度上影响其并发性能。

Two-Phase Locking

两阶段锁协议整个过程分为两个阶段:一是加锁,二是释放锁。加锁过程中事务只能加锁或者操作数据,在其通过某个锁定点之前都不能释放锁。而释放锁的过程中事务只能解锁或者操作数据,而不能再重新上锁了。

虽然两阶段锁协议比简单的锁定具有更好的并发性能,例如假设事务T1读取X,接着写Y,而事务T2只执行写入Y。在两阶段锁协议下,T2只能在T1两个动作之前或者之后发生。但事实上T2在T1两个动作中间进行与T2完全在T1之前进行的效果是一样的。允许所有可能的并发性同时确保的before-or-after atomicity规则很难设计。

锁与日志之间的关系有两点是需要考虑的:单个的中止事务和系统恢复。对于前者,协议要求中止事务在释放任何锁之前将其更改的数据对象恢复为原始值,因此不需要对中止的事务采取特殊的计算。至于后者,锁不是在非易失性存储中,因此在系统的恢复过程中必须将锁捕获以释放锁。然而我们还需要考虑的是,基于日志的恢复算法是否构建了正确的系统状态,因为系统崩溃可能是由于在崩溃之前提交的那些事务的串行排序引起的。

假设锁是在易失性存储器中,在系统崩溃的瞬间所有锁的记录都丢失。某些事务(记录BEGIN记录但尚未记录END记录的事务)可能尚未完成。但由于在那一瞬间所有事物的锁集合都是不重叠的,因此在恢复过程中可以不加锁地通过执行恢复算法重建系统状态,当然这一恢复过程中不能有新的事务产生。

Multiple-Site Atomicity: Distributed Two-Phase Commit

如果事务需要在分布式的环境下执行,则需要使用结合了persis­tent senders, duplicate suppression和single-site transactions的两阶段提交协议。

这是因为分布式架构中,不同的节点之间只能知道自己的操作是否成功,而无法知道其他节点的操作的成功或失败。为了保证事务的特性,需要引入一个作为协调者的组件来统一掌控所有节点(参与者)的操作结果并最终指示这些节点的最终提交。

第一阶段:提交请求的投票阶段

  1. 协调者向所有参与者节点发起是否可以提交事务的询问;
  2. 参与者执行相关的事务操作,并记录Undo和Redo日志;
  3. 各个参与对询问进行响应,同意或者终止;

第二阶段:提交执行的完成阶段

  1. 协调者节点向所有参与者节点发出"正式提交"/"回滚操作"的请求;
  2. 参与者节点正式完成操作/参与者利用Undo信息进行回滚,并释放在整个事务期间内占用的资源;
  3. 参与者响应完成信息;
  4. 协调者收到所有信息后,完成事务;

通信流程参考:

img

2PC也存在一些缺点,其中一个就是执行过程中,节点处于阻塞状态;另一个就是出现节点崩溃时,只能依赖协调者去进行回滚;并且协调者还存在单点故障的问题。