并发控制
并发控制协议必须能够保证冲突可串行性。并发控制协议一般可以分为悲观协议(pessimistic protocol)和乐观协议(optimistic protocol)两种,悲观协议使用锁来避免错误的操作,而乐观协议是在提交阶段采用验证器(certifier或validator)来保证正确性。一般情况下,从技术的角度来看,任何并发控制协议都可以很容易地扩展到分布式环境中。
封锁协议
对于每一个操作,事务(或并发控制调度器)都会申请一个锁,每个锁都有两种模式:读和写。两个读锁是相容的,而两个写锁或者一个读锁和一个写锁是不相容的。如果一个数据项没有以不相容的模式封锁,那么该数据项就可以授予锁。否则,存在一个锁冲突,并且事务处于封锁状态(会经历锁等待)直到当前的锁持有者释放锁。一个操作执行完成后,相应的锁就会被释放。锁本身不足以保证正确性。两段锁协议增加了下列条件,以下条件足以保证冲突可串行性[Eswaran et al., 1976]:
一旦一个事务释放了一个锁,该事务不能随即获取任何数据项的任何其他锁。
图2-9显示,在扩展阶段,事务所需要的锁的数量不断增加,在收缩阶段,锁的数据逐渐减少。
图2-9 两段锁
两段锁在很多商业化系统中广受欢迎,尤其是严格版本,在事务结束之前(即提交或中断),保留所有的锁。然而,两段锁可能会出现死锁。而且由于冲突操作的存在,数据项队列可能导致数据冲突。这种冲突可能导致系统抖动(在常规多道程序设计系统中,资源冲突一般是由内存、处理器、I/O通道引起的,而不是数据引起的冲突)。
乐观协议
如上所述,封锁可能造成长时间的资源阻塞。乐观并发控制协议可以允许事务执行所有操作,并使用验证方法来判断其他事务是否执行了冲突操作,通过这种方式可以有效避免这种阻塞。最简单的情况是,事务t1执行其所有操作(写操作会导致本地缓存更新)。当事务提交时,调度器会检查是否有活动的事务执行了冲突操作,如果有,就中止t1。
Kung and Robinson [1981]对上述简单思想进行了扩展,通过三个阶段来执行每个事务t1:
读阶段。在该阶段,事务可以无限制地读取任何对象,而写是本地的。
验证阶段。在该节点,调度器通过检查所有的并发事务t2从而确保没有冲突发生,即可以检查事务t2在其写阶段进行写操作的对象集合与事务t1在其读阶段进行读操作的对象集合是否重叠,如果有重叠,则中止t1。
写阶段。验证成功以后,值可以写入数据库中。
简单的正确性证明显示乐观并发控制可以确保事务的可串行化执行。该协议出现了很多种变体,而且由于乐观协议在数据资源上不会产生排它锁,因此,乐观协议在云计算环境中的应用越来越广泛