乐观复制算法-7.Operation-transfer系统中的调度和冲突处理
7.Operation-transfer系统中的调度和冲突处理
本章讨论operation-transfer系统中的操作调度算法,以及为达成一致的冲突操作解决。调度紧密地依赖可靠的组通信,向所有站点传播顺序定义良好的网络消息。实际上,TSAE(Time-Stamped Anti-Entropy protocol)作为一个组通信服务出现,尽管它很容易被理解为一个乐观复制服务。本书中呈现的语法更新调度,基本上对应全局广播和因果广播。语义更新调度对应与应用相关的因果广播,进而解决并发更新。(这句话翻译不是很确定,附上原文:Syntactic update ordering presented in this paper roughly corresponds to total and causal broadcast, and semantic ordering corresponds to causal broadcast with an application-specific policy to resolve concurrent updates.)然而,实现该策略的机制会非常不一样,因为乐观复制系统的工作方式是异步的,epidemic。
从一个相同的初始状态开始,结合相同的操作集合,当每一个节点计算出一个能获得一致最终状态的调度时,operation-transfer系统将取得一致。更准确地描述,我们需要下面属性:
1)对于所有节点,调度存在一个相同的前缀,我们称为共同前缀。(调度前缀相等,指他们包含相同的操作,同时他们可以从一个相同的初始状态开始,生成相同的状态。)
2)每一个操作最终会包含进入共同前缀,要么被执行,要么不被执行。
3)一旦进入共同前缀,操作不再被移除、也不再改变状态。
为了进行冲突解决,前面的定义允许调度将一个或多个操作无效化,比如,不执行它们。因此,如果两个操作冲突,一个或者另外一个将被无效化。一个更通俗的定义,允许冲突操作集被转化为不冲突的操作集。
这里有多种方法来产生一个相等的调度。一个充分条件是,调度的结果是完全一致的(假设,悲观操作)。语法调度策略,采用静态规则在全局进行更新调度,产生一个完全相同的调度结果。一个完全相同的调度结果,并不是保证调度相等的必要条件。(相等不等于完全相同。相等指的是不同节点调度后的更新,产生的结果是一样的;完全相同,指不同节点调度后的操作完全一样,包括顺序)语义调度需要深入操作语义,局部调度更新来消除冲突,产生相等的调度。操作转化,在7.3节中描述,修改操作本身,不需要重新排序从而让调度结果相等。7.4节讨论更新冲突解决策略。7.5节讨论更新提交(或者说,稳定化),该机制是让副本统一的调度结果被持久的应用到节点上,不用担心被撤销。
7.1 语法操作调度
操作调度的最低要求是调度结果兼容happens-before偏序关系(附件A.1)。语法调度策略通过静态调度规则实现最低要求。
很多系统为每一个操作记录一个标量时钟(比如,物理时钟、逻辑时钟;见Appendix A.2),使用它们来对操作排序,比如在Bayou,TSAE中。
(思考:注意State-transfer系统中,是为对象记录时钟,而不是为修改操作记录时间戳。)既然一个标量时钟无法检测冲突,这些系统必须采用一个独立的机制来检测冲突语义。
你或许认为可以采用Version Vectors来对操作更新进行排序和冲突检测,但它们却在Operation-transfer系统中并不常用。因为Multi-log通常已经记录了操作的语义关系,而Version Vectors提供很少的额外价值。
7.2 语义操作调度
一个不同的操作调度方法,是视调度为一个优化问题,为了消除冲突,实现一致。因此语义调度比语法调度要复杂许多,但可以消除冲突和重新排序不确定的操作。
7.2.1挖掘交换特性
最简单的语义调度是挖掘操作间的交换特性。两个操作known to commute a priori可以被以任意顺序调度,而不会影响最终结果。这样的特性在数据库系统很早就被使用,查询优化器通常会重新调度可交换的操作来产生更有效的序列。Wuu and Bernstein[1984]挖掘数据的交换特性,从而维护一个多Master,可复制的日志数据结构。在该数据结构中,插入和删除操作是可交换的,幂等的,这样调度就不是一个问题了。In GemStone,一个对象可以通知数据库系统它所含操作的交换特性。数据库检测可能的语法冲突,并忽略有数据类型申明的可以交换的冲突操作。
7.2.2典范操作排序
典范次序排序,根据应用语义对操作顺序给出正式形式化的描述。它被Ramsey and Csirmaz最先提出,他们对文件系统的乐观复制和协调进行了形式化描述。这里,日志和调度采用了一个形式化的代数关系进行描述,能准确地定义操作间的交换特性。举例来说,如果一个操作删除一个目录,另一个操作(在其它日志中)删除该目录的子目录,那么子目录必须比它的父亲先删除。当这里没有自然结构顺序,典范顺序将是随意的。(说明:自然结构顺序,比如说目录的父子关系)来自不同日志的两个操作(语义上)冲突,要么是他们不能互换,要么就是他们的结合破坏了文件系统结构。这很可能发生,比如,如果用户修改了一个文件,另一个用户删除了该文件的父目录。
调度Multi-log使得共享文件系统的各个副本,尽量的一致“as close as possible”。调度器忽略了重复更新。它不激活冲突操作,它们依赖于先前未激活的操作,并将冲突保存下来,由人工解决。
Ramsey和Csirmaz提出的操作很少,很简单:创建、删除、修改。虽然如此,他们整理51条规则。将他们的技术应用到一个更复杂的环境下是一个开放性问题。
7.2.3 IceCube中的语义调度
IceCube是一个与应用无关的复制工具,在基于操作的语义约束上计算最优的调度序列。IceCube支持两种类型的约束:
1)静态约束限制的是两个操作间的关系,不需要访问被更新对象的状态。在静态约束限制中,日志约束说明在一个日志中操作间的关系;即,它表示用户的意图。比如,一个日志约束可能加强两个操作间的执行顺序(前后约束),或者它会声明一个原子的更新单元(包裹约束),或者它可能会申明一些可选操作,供调度器选择(可选约束)。
一个对象约束,关系到对共享对象的修改操作。定义了四种对象约束:覆盖(两个操作更新了同一个对象),互换,互斥,最佳顺序(一个比其他顺序更好的执行顺序)。
2)动态约束,是一个断言,调度在执行时必须去进行判断该断言是否为真。它可被称为Bayou-style“依赖检查”,或经典的前置和后置条件。
举例说明,考虑一个旅行计划应用,采用IceCube运行在非连接网络环境下。用户可能会预订一个航班,为门票付费,以及计划在旅途中开一个会。在同一个session中,用户可能会设置一个不相关会议。当用户重新连接时,冲突可能会出现,原因可能有航班已满,不足够的资金,或者一个冲突的会议时间。
用户可以将三个相关的操作打包到一起,来表达他的意图,即当它们中任何一个失败时就取消所有的操作。这不相关的会议就不被打包到一起。如果另一航班具有相同的作用,则可以作为一个可选操作。共享日历实现它的语义,通过将不相融的会议交给用户手动排除。根据银行账户的语义,向账户中存入,和从账户支出两个操作,最好的顺序是先存入再支出。最后,银行设定一个动态的约束,用于支付门票的账户不能产生负值。
IceCube调度器,循环地选择和尝试满足静态约束的调度。如果一个动态约束不被满足,IceCube将跳过当前调度的执行,处理其他。使用静态启发方法,给予最可能成功的操作较高的优先级,根据静态约束规则以及最近动态约束判断失败的经验来选择最可能成功的操作。IceCube可以在1秒中调度上千操作。
7.3 操作转换
操作转换(OT)目标在于当调度结果不一致时保证最后结果的一致,操作是不能交换的,也不能被重新调度或者回滚。采用操作转换的典型应用是合作式文本编辑器,每一个操作包含字符改变发生的位置。假设,用户编辑共享字符串“abc”。用户1执行insert(“X”,1)产生“Xabc”,然后发送更新给站点2。用户2执行delete(1)产生“bc”,发送更新给站点1。站点2的执行结果是“Xbc”,与预期的一致。但站点1的结果是“abc”与预期的不一致。OT修改操作的参数,保持它最初的意图,尽力让所有节点效果一致,而不是考虑接收的顺序。这个例子中,OT发现insert和delete操作并发,它在站点1将delete操作修改为delete(2)。
OT十分复杂,高度依赖应用语义。转化一对冲突操作是与直觉紧密联系的,当有三个或者更多线程并发,转化的处理会更加复杂。有理由对这个文件进行形式化处理,采用cormack提出的微积分方法。比如,Palmer和Cormack证明了共享spreadsheet操作转换的正确性,支持所有常见的操作包括:更新cell值,添加或删除行或列,以及改变公式。
7.4 解决冲突操作
自然地,冲突解决是高度依赖应用的,很难进行概括。对于operation-transfer系统这一点特别的真实,因为operatio-transfer系统通常都会描述操作的语义。这一节我们讨论Bayou系统,并概括它将应用逻辑和可重用的冲突检测和调度算法分离的意图。
Bayou根据更新发生顺序进行临时的调度。它不进行语法冲突的检测。Bayou系统中的操作包括三个组成部分:一个数据库查询称为依赖性检测,一个数据库更新,和一段代码叫做合并过程。三个部分都由应用提供,运行在Bayou上。依赖条件判断负责处理检查语义冲突。通常,它检测当前的副本状态,对于用户来说是否可以接受当前的更新请求。比如,如果从银行账户划出账目,依赖条件会检查该款项是否超过用户定义的阈值,因为账户的余额可能在更新发起时变化。如果依赖条件判断成功,Bayou将执行更新。如果判断失败,合并过程将执行。合并过程可以执行任意必要的操作。比如,如果用户试图设定一个约会,依赖条件发现没有空余的slot,合并过程可以选择另一个slot。
在Bayou中编写一个合并过程并不容易。加在基于状态解决器上的所有严格限制会被应用。实践表明,即使为最简单的应用编写合并过程也是极其困难的。
7.5 提交操作
本小节讨论更新提交协议,比如当副本对一个等价的调度前缀达成一致是,将允许他们提交。提交有三个方面的作用。首先,系统的调度策略可能会产生非确定的结果,这种情况下,站点需要对最终应用的选择达成一致。其次,提交可以通知用户一个特定的操作最终被应用到所有的节点。第三,提交可以满足空间约束的限制,因为提交后的操作可以被安全地从multi-logs中移除。
7.5.1 Ack Vectors
确认向量与时间戳向量结合使用,从而使站点了解到其它站点的进展。站点i保存确认向量AVi,一个N个元素的时间戳数据组。AVi[i]定义为TVi[j]中最小的值,j属于{1…M}。表示,站点i接收了的更新中,没有哪一个操作的时间戳比AVi[i]更加新,无论更新来自哪个站点。确认向量,向TVs一样在节点间进行交换,通过成对的最大值比较而被更改。因此,AVi[K]表示站点i保守的估计站点K所接收到的最后更新。这样的定义下,所有时间戳早于 minAVi[j]的更新可以确定被所有站点已获取,它们可以被安全的重新排序,提交,和从multi-logs中删除。这个算法需要采用已同步的较宽松的物理时间,作为时间戳使用。否则,一个时间戳很慢的站点将拖延所有其它站点的确认向量。
(说明:原文这一段真没看懂)
这种算法比主提交协议要差(我们下面将介绍主提交协议)。首先,它只能被用于语法、基于时间戳的调用。它容易产生live-locking的情况。一个反应迟钝的节点,会拖延所有站点的确认向量,当站点增多时这种情况会更糟。
7.5.2 Primary Commit Protocol
Bayou实现了一个主提交协议。在这个协议中,所有站点对一个对象,在主站点上的更新取得一致意见(Bayou的一个事务不能访问多于一个对象)。主站点单方面的,从全局的角度对操作排序,并给予每一个它受到的更新,一个单调递增的提交顺序号CSN。这个主节点可以灵活选择任意的调度策略;Bayou使用语法的,基于时间戳的排序。操作与CSNs的对应关系,将通过日常更新传递给其它站点。一个非主站点,接收到CSN后可以按他们的顺序提交操作,并从multi-logs中删除。
需要注意该协议与单master复制的区别。在主提交协议中,所有的节点都是masters。即使在主节点无法到达的情况下,其它节点仍可以发起,交换,和临时地应用更新,因为主节点仅完成CSN的分配。
7.5.3 Quorum Commit Protocal
该协议由Deno提出,是悲观算法提交协议,但同样被应用在乐观环境中,因为它能在并不是全部节点都可用的情况下执行。在复制的每一步中,采用状态机方法,对于未解决的请求执行选举算法来提交每次请求。它给每一个<site,update>对分配一个权重,对于每一次更新总的权重是1.0。每个更新在所有节点周期性循环。当节点收到一个更新时,如果更新与本地其他已完成的更新没有冲突,该节点投票支持该更新。当节点观察到对于一个更新的权重达到一个阈值时,节点在本地提交请求,同时它发送一个确认通知给所有其他节点。
通常情况下,提交协议每次顺序地处理一个操作。当某个操作与已经提交的操作冲突时,它会被忽略直到他们能相互兼容。Denon允许在应用中声明操作的可交换性。模拟实验表明,该协议表现的与经典primary-copy策略十分相似。