6.2.3 并发控制
(1)读事务
Megastore提供了三种读取模式:最新读取(current read)、快照读取(snapshot read)、非一致性读取(inconsistent read)。其中,最新读取和快照读取总是在单个实体组内完成的。在开始某次最新读取之前,需要确保所有已提交的写操作已经全部生效,然后读取最后一个版本的数据。对于快照读取,系统取出已知的最后一个完整提交的事务版本并读取该版本的数据。与最新读取不同的是,快照读取的时候可能有部分事务已经提交但没有生效(REDO日志同步成功但没有回放完成)。最新读取和快照读取利用了Bigtable存储多版本数据的特性,保证不会读到未提交的事务。非一致性读取忽略日志的状态而直接读取Bigtable内存中最新的值,可能读到不完整的事务。
(2)写事务
Megastore事务中的写操作采用了预写式日志(Write-ahead日志或REDO日志),也就是说,只有当所有的操作都在日志中记录下来后,写操作才会对数据执行修改。一个写事务总是开始于一个最新读取,以便于确认下一个可用的日志位置,将用户操作聚集到日志缓冲区,分配一个更高的时间戳,最后通过Paxos复制协议提交到下一个可用的日志位置。Paxos协议使用了乐观锁的机制:尽管可能有多个写操作同时试图写同一个日志位置,但最后只有一个会成功。其他失败的写操作都会观察到成功的写操作,然后中止并重试。
写事务流程大致如下:
1)读取:获取最后一次提交的事务的时间戳和日志位置;
2)应用逻辑:从Bigtable读取并且将写操作聚集到日志缓冲区中;
3)提交:将缓冲区中的操作日志追加到多个机房的Bigtable集群,通过Paxos协议保证一致性;
4)生效:应用操作日志,更新Bigtable中的实体和索引;
5)清理:删除不再需要的数据。
假如有两个先读后写(read-modify-write)事务T1和T2,其中:
T1:Read a;Read b;Set c=a+b;
T2:Read a;Read d;Set c=a+d;
假设事务T1和T2对同一个实体组并发执行,T1执行时读取a和b,T2读取a和d,接着T1和T2同时提交。Paxos协议保证T1和T2中有且只有一个事务提交成功,假如T1提交成功,T2将重新读取a和d后再次通过Paxos协议提交。对同一个实体组的多个事务被串行化,Megastore之所以能提供可串行化的隔离级别,得益于定义的实体组数据模型,由于同一个实体组同时进行的更新往往很少,事务冲突导致重试的概率很低。