3.基本定义
这一节介绍一些重要的词汇。3.1节说明对象,3.2节定义冲突,3.3节对冲突处理技术进行分类。
3.1 对象
任何复制系统都有一个最小更新粒度的概念,有些系统表示为可识别的粒度,有些系统表示为可传播更新的粒度。文中我们称最小的粒度为对象。不同系统的对象可能差距巨大。比如,文件同步中,一个典型的对象是一个目录或者文件。在groupware系统中,相同的文件会被视为一个包括许多对象文档;比如包含:段,行和字符。有些系统将操作不同层次的粒度;比如CVS,同时操作文件和行对象。
在某些系统中,对象的边界和区分是内容相关的。比如,一个协作的文本编辑器,一个对象可能是文件中的一行,并通过一个行号进行区分。因为用户会并发修改文件内容,系统会对相同位置在不同文件内容中给予不同的标记号。这样相对标记方法,给冲突解决增加了很大的难度,这一点在7.3节操作转化的讨论中将会证明。
一个副本是一个对象的拷贝,并存储在站点上,比如,计算机中。一个站点可能存储多个对象副本。文中,会交换的使用副本和站点这两个概念。大部分的乐观复制算法会独立地管理各个对象。
(思考:最后一句话是说每个乐观复制算法的实例,其管理的更新对象是不同的。)
3.2 一致性和冲突
一个乐观复制系统允许副本存在分歧,比如,不同的值。在但Master系统中,分歧往往是良性的,结果仅仅是访问延迟。本文主要论述多Mater系统,分歧将导致错误,或者冲突。本章将给出在多Master系统中,冲突的更准确描述,以及它与并发访问和共享数据语义的关系。
为了不同目的,存在多种冲突的定义,但它们有两个共同点。首先,冲突的定义无法与一致性向分离,因为冲突出现在操作违反了一致性时。其次,一个操作与另一个操作存在“happened-before”关系,则两者间不存在冲突。换句话说,如果一个操作A能观察到另一个操作B的影响,系统认为操作A已经将操作B考虑进来了。这里,分歧可以从两个维度上定义。
Internal vs. External (内部vs外部)一致性:大多数系统支持的对象相互独立,分离,并采用唯一ID标示。对象的相互独立指,当程序修改多个对象时,更新不能原子性的应用到多个对象上(不是一个原子事物)。对每一个对象的更新单独传播,可能会存在不同的冲突解决结果。
大多数乐观复制系统认为对象相互独立,对于分裂数据的操作将不会冲突。(思考:对不存在依赖关系数据的修改将不会出现冲突,依赖关系可以有很多种。比如,目录结构的父子关系、信用卡转账两个账户的依赖等等)他们支持内部一致性,副本间相同的对象。典型的例子是复制文件系统,对不同文件的更新不会冲突。其它系统试图维护跨对象的不变性,external一致性。比如,一个复制数据库使用事务来保证对多个对象更新的原子性。
语法 vs 语义检测:仅通过并发更新的出现来标示冲突的系统,检测的是语法冲突。比如,文件系统对同一文件的任意并发写冲突,适用这种策略。语义冲突检测,利用应用语义从良性并发更新中区分出冲突。比如,采用语义冲突检测的文件系统,允许对同一目录下不同文件的并发更新;创建文件“X”与删除文件“Y”不会冲突。
两两结合的四种组合都是有意义的。内部-语法系统是最流行的,因为非常容易实现。因为内部一致性不会考虑不同对象的关系,用户可能会观察到令人吃惊的结果。考虑一个持久的Hash表,每个文件有一个Hash表以及溢出的桶。一个插入操作会同时更新两个文件;在这两个文件上,并发的插入操作可能会按不同的方式处理,从而导致一个不一致的Hash表。(说明,这句话翻译的不一定对,下面是原文:Consider for instance a persistent hash table where one file contains the table and another the overflow buckets. An insert operation updates both files; concurrent inserts may be resolved differently at the two files, resulting in an incorrect hash table. )
虽然如此,支持外部一致性在乐观复制系统很少见,因为它需要额外的机制来维护和检测内部对象的约束。第8章将会简要的说明。本文主要考虑内部一致性,除非有明确的说明。
(思考:Dropbox等文件同步工具,实现的是文件目录同步。对于目录删除,目录丢失情况的处理就需要处理外部对象的约束关系,即文件和目录之间的约束。)
(思考:我们实现的Robin对于语法上的冲突,采用Thomas规则。对于违反happen-before关系的冲突修改,则是基于语义来处理。)
(思考:我们实现的Robin维护的文件系统语义一致性主要是三点;目录与文件的父子关系;同一目录下不能出现同名文件、同名目录;对同一文件不能多个用户同时修改(只要违反happen-before关系的修改都判定为并发修改);)
3.3 冲突处理技术的分类
图3,给出了冲突处理方法的分类。分为三个基本阶段:避免,检测,和修复冲突。
冲突避免是最好的方法,尽管通常在乐观环境中不能。悲观算法和单Master系统采用传播更新前串行化更新的方式来避免冲突。尽管阻止冲突是不可能,系统通过快速地传播更新从而可以减小副本之间的差异。另一个可选方法,将对象划分为更小的片段,能减少false-positive冲突;比如,对同一对象不同部分的更新并不冲突(见5.3节)。最后,有些系统能预估不一致的程度,当超过设定阈值时会提醒用户(见8.2节)。
如果冲突不能避免,他们应当可以被检测和修复。语法冲突可以采用自动机制来检测,比如two-timestamps(5.2.2小节)和version vectors(5.2.2小节)。语义机制可以过滤掉一些语法冲突,根据对象语义他们并不冲突。例如包括,检测可交换的更新,采用有利的顺序。当操作并不可直接互换时,操作转化方法修改冲突操作的参数,使他们以其他顺序执行。
冲突更新必须被解决。解决方法不必依赖于冲突的检测;系统可以简单的使所有可能与其它操作冲突的更新无效,比如,采用“last writer wins”策略。一些高级的系统支持应用相关的自动冲突处理。某些情况下,冲突不能被自动解决,最终将询问用户或者管理员来手动解决冲突。
4.单Master系统
本章讨论单Master系统的设计问题。单Master系统设计一个副本作为Master,所有更新发生在该节点。对于单Master节点,更新传播和调度是没有什么价值的,因为数据通路只有一条,从master到slaves。最简单的设计是state transfer,比如DNS的传输,NIS,以及WWW/FTP镜像。当Master更新一个对象时,分配给该对象一个新的时间戳。Slave的时间戳标记它目前拥有对象的版本。Slave节点周期性地拉取master,如果它的时间戳与master的不同,则从master处获得新的内容。另一种方式,每次对象更新,master向slaves推送更新,比如在DNS主动推送,或者NIS。单Master,操作传输同样存在于关系数据库系统,以及最近的DNS实现中。
冲突检测和解决对于单master系统不是问题,因为master节点可以立即检测和延迟并发更新,或者忽略并发更新。当系统需要处理频繁地,针对共享对象的写操作时,这样的特性让单master系统具有较好的扩展性。
不好的方面,master节点存在单点故障和性能瓶颈。但是,当系统开发需要最小化,或者服务基本由读请求组成,单Master复制仍十分有用。