经典分布式论文阅读:Bayou

本文是Bayou论文的阅读笔记,Bayou是一个多副本弱一致性存储系统。Bayou主要在弱连接的移动计算环境下,给协作应用提供管理冲突的并行活动。在弱连接的网络环境下,其实也只能实现弱一致性副本。在Bayou中,客户端能够在任何情况下读取数据,即使这些数据中的冲突没有完全解决。本文的主要贡献为:

  • 引入在更新数据时依赖检查和合并过程进行应用定义的冲突检测和消解;
  • 定义了更新的两种状态:提交试探
  • 如何管理两种状态的更新;
  • 副本如何走向最终一致;
  • 如何在Bayou中保证安全性(笔记略)。

Bayou应用

  • 会议室调度:会议室调度程序允许用户预定会议室。如果用户申请的会议室在指定时间有冲突,那么会重新安排到备选的时间段。
  • 文献数据库:文献数据库允许用户协同维护一个文献数据库,维护一个标识符到文献条目的映射,如果存在冲突的标签,那么将冲突的标签自动重命名。

Bayou基本系统模型

Bayou系统的数据集合会在一定数量的服务器上保存副本,应用程序通过API和服务器交互。API提供了两种操作:读和写。Bayou使用了弱一致性副本模型,提供了任意读写访问。客户端会访问不同的服务器进行读写,需要使用Session Guanrantees来保证客户端观察到的一致性。

为了实现应用层面的冲入检测和消解,更新操作需要提供用于检测和消解冲突需要的额外信息。服务器之间会使用逆熵协议相互交换记录的写入操作,只要服务器之间不存在永久的分裂,那么写入操作会最终到达全部的服务器。

冲突检测和消解

支持应用定义的冲突检测和消解是Bayou设计的重点,冲突检测和消解的机制分别是依赖检查合并过程

  • 写入操作的执行过程:
Bayou_Write (update, dependency_check, mergeproc) {
    IF (DB_Eval (dependency_check.query) <> dependency_check.expected_result)
        resolved_update = Interpret (mergeproc);
    ELSE
        resolved_update = update;
    DB_Apply (resolved_update);
}
复制代码
  • 一个写入操作:
Bayou_Write(
    update = {insert, Meetings, 12/18/95, 1:30pm, 60min, “Budget Meeting”},
    dependency_check = {
        query = “SELECT key FROM Meetings WHERE day = 12/18/95
AND start < 2:30pm AND end > 1:30pm”,
        expected_result = EMPTY},
    mergeproc = {
        alternates = {{12/18/95, 3:00pm}, {12/19/95, 9:30am}};
        newupdate = {};
        FOREACH a IN alternates {
            # check if there would be a conflict
            IF (NOT EMPTY (
                SELECT key FROM Meetings WHERE day = a.date
 AND start < a.time + 60min AND end > a.time))
CONTINUE;
# no conflict, can schedule meeting at that time
newupdate = {insert, Meetings, a.date, a.time, 60min, “Budget Meeting”};
BREAK;
}
        IF (newupdate = {}) # no alternate is acceptable
newupdate = {insert, ErrorLog, 12/18/95, 1:30pm, 60min, “Budget Meeting”};
        RETURN newupdate;}
)
复制代码

依赖检查

如果服务器在当前数据上的查询没有返回想要的结果,那么就意味着产生了冲突。Bayou的依赖检查可以检测写入-写入冲突读取-写入冲突,因为依赖检查可以做任意查询,因此可以实现数据上高度灵活的约束。

合并过程

当检测到冲突之后,服务器会执行合并过程。当冲突无法自动合并时,冲突会被记录到日志中,从而让人工去消除冲突。

副本一致性

Bayou实现的上最终一致性,主要通过两条原则保证:

  1. 写入操作在所有服务器上有一个一致的顺序;
  2. 冲突检测和合并过程都是确定的,因此每个服务器都会以同样的方式来消解冲突。

Bayou服务器接收到的写入请求最初是试探状态,最终才变成提交状态。每个写入操作都会打上标记<时间戳, 标记的服务器ID>,服务器使用的是逻辑时钟,通常和真实时间同步,但是在服务器从逆熵过程中收到写入操作后,需要前推它的时钟。当服务器通过逆熵协议收到新的写入之后,需要通过撤销写入来重新按顺序应用写入操作。

写入稳定性和提交

当写入操作被服务器最后一次执行之后,写入操作认为进入稳定状态,意味着服务器已经收到了在这个写入之前的所有写入操作。

检查写入是否稳定可以通过逆熵协议完成,服务器交换用于最新写入操作的时间戳,当一个写入操作时间戳低于全部服务器时间戳时,那么这个写入是稳定的。对于每个数据,选定一个主服务器,让其他服务器通过它交换提交的写入。

存储系统实现

存储系统由三部分组成:写入日志、元祖存储和撤销日志。

  • 写入日志:包含排好序的服务器收到的写入请求;
  • 元祖存储:包含当前写入的执行结果;
  • 撤销日志:用来撤销写入操作。

当写入变为稳定之后,请求就可以在日志删去。元祖存储采用内存关系型数据库实现,保存了提交全部两个版本的数据库,它们数据保存在一起,使用两个字节来标记提交或者全部。撤销日志能够撤销之前写入元祖存储的更改。为了实现故障恢复,需要保存写入日志和元祖存储检查点到稳定存储中。

  • 将写入应用到数据库
Receive_Writes (writeset, received_from) {
    IF (received_from = CLIENT) {
        # Received one write from the client, insert at end of WriteLog
        # first increment the server’s timestamp
        logicalclock = MAX(systemclock, logicalclock + 1);
        write = First(writeset);
        write.WID = {logicalclock, myServerID};
        write.state = TENTATIVE;
        WriteLog_Append(write);
        Bayou_Write(write.update, write.dependency_check, write.mergeproc);
    } ELSE {
        # Set of writes received from another server during anti-entropy,
        # therefore writeset is ordered
        write = First(writeset);
        insertionPoint = WriteLog_IdentifyInsertionPoint(write.WID);
        TupleStore_RollbackTo(insertionPoint);
        WriteLog_Insert(writeset);
        # Now roll forward
        FOREACH write IN WriteLog AFTER insertionPoint DO
            Bayou_Write(write.update, write.dependency_check, write.mergeproc);
        # Maintain the logical clocks of servers close
        write = Last(writeset);
        logicalclock = MAX(logicalclock, write.WID.timestamp);
    }
}
复制代码

参考文献

  1. Terry, Douglas B., et al. "Managing update conflicts in Bayou, a weakly connected replicated storage system." SOSP. Vol. 95. 1995.

猜你喜欢

转载自juejin.im/post/5d21399cf265da1bac403905
今日推荐