在动态网络下实现分布式共享存储
http://cacm.acm.org/magazines/2014/6/175173-implementing-distributed-shared-memory-for-dynamic-networks
译者序 共享内存系统是普通单机程序开发者熟悉的开发范式,通过简单的使用读、写命令,就能确保将我们须要的值从内存中放入和读取出来,数据的一致性等问题,在单机系统中,开发者根本不须要考虑,比方你不须要考虑当你进行了i=i+1后,再获取i的值时,i的值可能还没有来的及变化,由于这些都已经在读写原语的原子性中被考虑了,然而在分布式环境下,由于数据出现多个副本,且副本的数量有可能动态增加和降低,要实现同样的功能,又能保证读写性能,就须要新的算法和实现。本文介绍了分布式环境下实现共享内存模型会遇到的各种问题和挑战,针对不同问题,介绍多种算法,并比較其优劣性。终于选取两种实现进行实际測评。本文是对现阶段该领域研究现状的整体介绍,通过阅读该文,我们能够了解动态分布式共享内存研究的前沿状况,了解该领域中的挑战与机遇,是有志于分布式领域的架构人员,开发者,研究人员的必读资料。
这些干扰包括:某些电脑退出工作,动态改变系统中參与计算的工作集合,通讯链路的失败和延迟。
共享内存服务是大多数信息时代系统的核心,我们这里所具体分析的共享内存系统支持两种存取操作:读(read)操作获取对象的当前值,写(write)操作替换对象的旧值为当前新值。操作中涉及的对象往往被叫做寄存器(registers)。尽管我们不打算包括很多其它复杂的对象语意,比方事务或者整合的读改写操作,可是不论什么分布式系统实现都须要接受以下谈到的挑战。
想象一个中心server类型的存储系统实现,server接收client请求并对数据进行处理,然后回复。尽管概念简单,但这样的实现会产生两个基本的问题。第一个是中心server是性能瓶颈,第二个是server本身是单点故障。这样的实现方式下,服务质量随着client的增加显著下降,假设server崩溃,服务将无法使用(想象一下网络新闻服务假设设计为中心server结构,其结果将难堪重任)
因此系统的重中之重在于保持可用。这就意味着他必须具备一定的容错性,比方,系统必须能够屏蔽掉某些server的错误或者通讯失败。系统必须支持大量并发訪问,并不会导致剧烈的性能下降。唯一能保证可用性的方法仅仅有冗余,也就是说使用多个server,并在server间制造对象内容的副本。另外数据复制必须从地理上分散开来,并位于不同的网络位置,才干让系统屏蔽某些数据server子集的失效。
保证数据长期有效也非常关键。一个存储系统可能容许一些server失效,可是长远来说,我们能够想象,全部server都有可能被更换,由于没有server是永远可靠,或者由于计划中升级。此外,在移动环境下,比方搜救或者军事行动中,非常可能须要将数据从一个server集合迁移到另外一个,使得数据能够依据须要移动。不管我们关注的是数据的长期有效性还是移动能力,存储系统必须要提供数据的实时无缝迁移:没有谁能够让世界停止运转,以便等待他慢慢又一次配置系统以应对系统失效或者环境变化。
由数据副本带来的主要问题是一致性问题,系统怎样才干从多个副本中找到最新值?这个问题在单server中心的实现中不会出现:一台唯一的server永远包括最新的值。在多数据副本的情况下,有可能须要询问每一个副本才干找到对象的最新值,可是这个办法代价太大,并且也做不到容错,由于必须要求每一个节点都能被訪问。不管怎样,所以的实现对client都应该是透明的,client幻想着正在操作一个单副本对象,并且全部的存取操作都一个接一个按顺序运行,不论什么读取操作都能返回前一个写入操作的结果,并且该值和前一个读操作所获得的值至少一样新。总的来说,对象的行为,从外部看起来,必须和对象的抽象序列化数据类型一致,这样在开发使用这些对象的程序时才干放心的使用这些对象类型。一致性的概念通过原子性(atomicity28)或者等效的线性一致性(linearizability.25)来实现。
毋庸置疑,原子性是的最方便的一致性概念(是一致性中最强的概念),我们也注意到,基于效率的考量,一些相对较弱的一致性概念也被提出并实现。比方在多处理器内存系统领域,出现了几个不是那个直观的定义,他们的出现主要是基于一个有趣的理念:“没有人能找到解决一致性的方法,可是内存訪问速度非常快。”原子性提供最强的保障,也导致事实上现花销高于较弱的一致性保障4 。Eric Brewer猜想没有分布式系统能够同一时候实现一致性,可用性,分区容忍性;这就是著名的“CAP猜想”,这个猜想如今已被证明成为了定理23 。因此在一些情况下,较弱的一致性模型须要被考虑8 。尽管如此,我们觉得实现简单和直观的原子一致性仍然非常重要。
这样的情况让人想起了编程语言发展的造期,汇编语言被觉得更加优秀,由于他能产生更有效率的代码,或图形界面的早期,命令行界面被觉得更优秀,由于他们消耗更少的资源。可想而知,在原子性领域的相似争论迟早也尘埃落定。当故障是间歇性并且存在时间较短的时候,我们能够像处理长时间网络延迟一样处理它,把恢复工作交给底层的网络模型。假设故障是永久性的,一致性仍然能够通过将服务限制在主要分区(partion)来实现。在近期的一次演讲中30 ,ACM的 2008图灵奖获得者Barbara Liskov说,尽管原子性实现代价确实较高,但假设我们不保证原子性,开发者会非常头痛。
有趣的是已经有存储系统提供了原子化的 读-改-写 操作原语,这样的存取原语的实现比我们涉及的读写原语要强大得多,只是实现代价也非常高,当中核心部分原子化的更新操作,有多种不同实现,有的将系统的一部分改为单一写模型(比方微软的Zure9),或者依靠始终时钟同步硬件(如Google Spanner13),或依赖如vector clocks这样的复杂机制来解决事件的顺序问题(Google's Spanner13)。我们对读写原子性的阐述展示了分布式存储系统面临的一般性挑战。我们将该系统建模为一些互相连接的电脑或节点,互相之间使用点对点消息进行通讯。每一个节点都有一个唯一的标示符(比方IP地址)、本地存储并能进行本地计算。计算中,某个节点可能随时故障 ,节点故障意味着:节点不进行不论什么内部计算,不发送不论什么消息,不论什么发送给它的消息都不会被成功接收。
系统是异步的,节点不读取全球时钟,也没有同步机制。这意味着不同节点的处理速度是随机的,节点也不知道本地计算任务的时间上限。消息的延迟也是随机的,节点也不知道消息延迟的上限(尽管限制可能存在)。因此,算法不能假设知道全球时间或者延迟,由于不同节点的处理速度和延迟都不确定。
我们假设消息在传输中是有序的。消息不会自发的出错,重复或者生成。随意一条被收到的消息一定在这之前被发送过。消息不会无故丢失,可是消息的丢失能够被看做是长时间的延迟的后果(怎样利用重发机制或者gossip协议建设一个可信的通信服务不是本文的讨论范围)
我们将分布式网络系统分成动态和静态的两类,分类标准例如以下。静态网络系统中,节点的集合是固定的,每一个节点可能知道其它全部參与节点的信息。节点崩溃(或者主动退出)会导致节点被从系统中删除。动态为网络系统的节点数是不固定的,随着时间变化,由于节点崩溃,退出以及新节点增加,系统的參与节点有可能全然变化,并且这些变化可能随时发生。
我们先不假设动态环境中的故障程度,留待解决方式完整提出后再行讨论。不管动态与否,系统的一致性都须要被保留。计算过程产生的干扰可能对所讨论的内存服务的性能产生负向影响,只是内存的存取操作在某些假设被满足的情况下一定会终止。比方,当超过半数数据副本被激活,且网络延迟可控,静态内存服务将保证内存操作停止。动态内存服务不须要超过半数数据副本被激活,可是要求在特定时间内,多数数据副本处于激活状态(比方某法定数量(quorums))。假设这些假设不能被满足,内存服务须要依旧保证操作的原子性,只是操作所需的时间会显著增加,或永远无法停止。
总的来说,我们觉得全部參与工作的节点都是“好同志”,他们既有能力,又愿意參与工作,并且不会有意无意的捣乱---有益进行错误的计算。因此我们不用採取措施来处理恶意行为。假设你觉得參与者有可能干坏事,我们建议对这方面感兴趣的读者阅读相关的文章,Rodrigues et al.,35 Martin and Alvisi.34
分布式共享内存和一致性。一个分布式共享内存服务利用网络节点和节点间通讯,模拟一段共享的内存空间,空间包括一系列能够读写的对象(经常被叫做寄存器(registers)),服务使用多个数据副本来保证数据的存在性和可用性。对client来说,服务是隐形的。对象的内容被拷贝到多台不同的server或者副本主机上,client发起读写操作。发起读操作的client被称作阅读者(readers),发起写操作的client被称作写入者(writers),一个client可能既是reader又是writer.
为了响应client请求,服务端发起一个包括与副本主机间通讯。这个通讯协议就是内存系统能够保证一致性的关键所在。原子一致性要求每一个操作“缩水”为一个序列化点,这些序列化点的运行顺序必须和真实操作的顺序一致,终于的操作结果必须与序列化操作的结果一致。具体来讲,当一个读操作在一个写操作完毕后被调用的话,读操作的返回值必须是那上述写操作写入的值,或者是上述写操作之后,读操作之前其它写操作的值。另外,假设读操作在另外一个读操作之后被调用,其返回值必须与前一个读同样,或者是一个比刚才的值更”新”的值。(在ACM 数字图书馆的附录里有更正式的论述)。由于这些自然属性,原子性是最简便和直观的一致性保证。
数据拷贝引起的最大问题就是一致性,我们怎么保证系统在不同拷贝间找到最新的值? Lamport 28 引入了原子寄存器(registers)。Herlihy 和 Wing26 ,提出了一个等效的定义,线性化性(linearizability),这个也将原子性扩展到了随意的数据类型。由于原子性是关于一致性最强的概念,提供最实用的訪问语意,所以我们聚焦于原子性的共享内存系统。为静态环境设计的算法仍然须要适应一些动态的行为,比方有限的异步性、临时故障、永久崩溃等等。我们在这里先讨论静态环境下的共享内存服务有两个原因:首先,为讨论动态内存打下一个基础,同一时候聚焦某些实现原子性的方法,这些方法在动态服务中也会用到。第一个针对静态内存共享系统综合考察来自Chockler et al.12 。他的著作中提到的拷贝存取算法能够作为我们动态系统的基础材料,然而为静态系统设计的算法不能被直接用的动态系统,由于他们缺乏处理拷贝集合变化的能力。Attiya, Bar-Noy 和 Dolev,3 提出了处理共享内存的原始算法,这个算法被称作ABD算法,这项工作使得他们于2011年获得了Dijkstra 奖。
这个算法实现了原子内存,同一时候拷贝提升容错能力和可用性。给定的总拷贝数是n,系统能够容忍 f 个拷贝失效,n>2f,。我们的报告包括Lynch and Shvartsman32对原始算法做出的改进。 每一个副本主机i 都保存寄存器(register)的本地值,valuei 以及一个附加到副本上的tag,tagi = 〈seq, pid〉,seq是一个序列号,pid是写入节点的唯一标识。Tags依照词典顺序进行比較排序。每一次新的写入都分配一个唯一的tag,发起节点的id被用来打破可能出现的无限循环。这些tags被用来确定写操作的顺序,也能同一时候决定相应读操作的返回顺序。 共享内存服务的client应该幻想自己在使用一个单拷贝对象[?],对此对象的全部存取都是序列化的. 读取(Read)和写入(Write)操作相似,每一个操作都由两个阶段组成,一个获取(Get)阶段,用于从多个拷贝中获取信息,一个放入(Put)阶段,将信息传播到全部可用拷贝中。每一个阶段的协议都保证超过半数的可用节点參与通讯交换:首先信息被发送到全部可用拷贝主机,接着全部可用拷贝主机的响应会被收集起来。前面提到过由于n>2f,所以一定存在超过半数的未故障节点。因此,每一个阶段会在一轮通讯后停止,随意一个操作,会在两轮通讯后结束。这样的实现方式的正确性,即原子性是这样被保证的:对于随意两个连续操作,至少一个正确的副本会在第一个操作的put阶段中被更新,又被第二个操作的get阶段所读取(译者:两次操作至少共享一个节点);这就保证了第二个操作总会“看见”近期的前置操作的结果。我们能够发现,在与不同主机集合通讯时,[?]须要要求随意两个集合之间有交集。假设等待超过半数的可用主机响应过于消耗资源和时间,能够设定一个法定数量系统(quorum system).32,38 (具体和完整的伪代码能够在ACM数字图书馆的附件中找到)接下来,我们介绍几种能够在更加动态的系统中提供一致性共享内存的方法,更加动态的系统是指不仅节点可能崩溃或者自发的退出服务,并且新的节点可能随时增加服务。总的来说,对象拷贝集合的数量可能随着时间进行变化,终于迁移到全然不同的拷贝主机集合上。ABD算法不能应用在这个场景中,由于它建立在原有的拷贝主机集合一直可用的基础上。为了能够在动态环境中使用相似ABD方法,必须要提供方法对复制主机的集合进行管理,并保证阅读者(reader)和写入者(writer)能訪问可用的集合。
有必要指出,处理动态环境以及管理节点集合并不直接解决内存服务一致性的问题。这些问题代表着动态分布计算领域面临的更加广泛的挑战。这也启示我们:实现共享内存的一致性有时能够使用分布式的基础工具,比方那些用来管理參与节点集合的工具,提供通讯原语的工具以及在动态分布式环境中获取共识(consensus)的工具。Aguilera et al.1提供的教程中涵盖了当中的若干主题。
我们首先从获取共识(consensus)的问题開始,由于它通过建立共同的操作顺序,为实现内存服务的原子性提供了自然的基础。也由于共识(consensus)也被用于原子化内存实现的其它方面。接着,我们我们将提出组通讯服务(GCS)解决方式:使用强通讯原语,比方全然排序广播,来对操作排序。最后,我们聚焦一些方法,这些方法通过用显式的拷贝主机集合管理,能够用于扩展ABD算法至动态环境。
在分布式环境中怎样协调并达成一致是计算机科学的基本问题。在分布式环境下达成一致的问题被称作共识问题。由于不同节点提供了多个參考值,一组进程须要对该值达成一致。
不论什么解决方式都必须保证以下几个属性:【译者,此处定义翻译參考pixos算法调研报告】一致性:至多有一个值被通过,即两个不同节点不能够通过两个不同的值;合法性:假设一个值被通过,那么这个值一定是由某个节点提出过的。即仅仅有被提议过的值才会被通过;终结性:每一个未发生问题的节点都会终于通过某个值,即一致性算法能够取得进展。共识在设计分布式系统时,是一个强大的工具,33,可是在异步系统中,共识问题的难度也臭名昭著,由于当一个进程出现故障时,终结性非常难被保证19 ;所以共识必须小心使用(一个解决共识的方法是引入“错误探測器”,它能提供或者说限制关于节点的信息10。
共识算法能直接被应用于原子化的数据服务,我们仅仅须要让參与者对全局全部的操作顺序取得一致.29 。不管使用哪种共识的实现,正确性(一致性)都能够被保证,可是了解下层系统的特征能够指导我们选择性能更好的实现(要知道各种实现的精妙之处,请參见e Lynch33)。不管怎样,每一个操作都使用共识是一个笨拙的实现方式,特别是一些干扰会延迟甚至阻止操作终止。因此使用共识时,须要尽量避免与某些的内存操作一同使用,并使得操作不影响共识的终结。我们应该注意到,实现共识比实现原子操作更为复杂,特别是两个或者两个以上操作的共识问题不能通过原子读写寄存器来实现31。
在分布式系统中最重要的基础材料就是组通讯服务(GCSs)5 ,GCS使得在不同节点上运行的操作共同以组的方式工作。操作通过GCS多播服务发送消息到全部组成员以实现分组协作。GCSs 负责保证消息传输的顺序和可靠性。
GCS的基础是组成员服务。每一个进程,在每一个时间都有一个唯一的组的视图(view),视图包括该组中的操作列表。视图能够随着时间变化,有可能在不同的进程中视图也不同样。GCS引入的还有一个重要的概念是虚拟同步性 (virtual synchrony )【译者,參考wiki文章】,其核心要求是通过两个连续的视图同一时候处理的操作发送同样的消息集合。这样接收者就能依据消息、组成员,应用程序预设规则进行协同合作5。
GCS提供一个方法来实现动态网络的共享内存。其方法例如以下,比如,在GCS视图同步(view-synchronous GCS)18基础上实现一个全局的、全然排序的多播服务(发给每一个视图的消息都附加了一个总顺序,每一个參与者收到一个包括这个顺序的前缀)。有序组播是用来对存储器存取操作进行排序,以产生原子性的内存。这样的解决方式的主要缺点是,对于大多数GCS实现,形成一个新的视图须要大量的时间,在此期间client的内存操作会被延迟(或终止)。新视图的形成通常须要几个回合的沟通,在典型的GCS实现中,即使仅仅有一个节点故障,性能下降也非常明显。在内存服务中,最好能保证读写操作在重构(reconfiguration)时能正常进行,具备一定程度容错而又不产生性能下降是最理想的。还有一种方法是将GCS与ABD算法整合。比如,由De Prisco et al.14所描写叙述的动态原始配置(dynamic primary configuration GCS ) , 在每一个配置中使用技术Attiya3以实现原子内存。在这里,一个配置与一个Quorum系统组相结合。配置能够随时改变,由于系统的动态性质或由于须要一个不同的法定人(quorum)数系统,就像和其它以GCS为基础的解决方式一样,读取和写入在重构时被延迟。最后,不论什么新的配置与曾经的配置有交集。这就影响重构的灵活性,可能须要过渡的配置的变化以达到终于所需目的。
Birman6提出了一个关于动态服务复制的通用方法Paxos29 ,这样的重构模型结合了虚拟同步(virtual synchrony )与状态机副本,以解决共识问题。
dynastore2是多writer/多reader的动态原子存储服务的实现。它集成了ABD算法,并同意副本主机集合重构,并且不须要共识的使用。
參加者从一个默认的本地配置開始,即一套副本主机。该算法支持三种操作:读,写,和又一次配置。读和写操作分为两个阶段,假设不考虑又一次配置,协议与ABD相似的:它使用超过半数的ABD的副本,每一个副本保持对象的值和相关的标签。
參与者使用重配置操作(reconfig)来改动当前配置,(+,i)表示副本主机i增加,(–,J),表示主机j移除,reconfig分为两个阶段,阶段一使用一个分布式的弱快照服务发表由update原语引起的变化,阶段二通过scan原语获得由配置中的其它成员提交的变化。快照服务本身不是原子的,它不会为update操作进行全局排序,同一时候scan操作不能保证反映全部曾经完毕的update。然而,快照服务足够建立一套有向无环图(DAG),作为參与者的一种状态,存储于每一个參与者中。图的顶点相应一种配置,图的边意味这对配置的改动【译者注:c1->(+,i)->c2-(-,j)->c3 c是配置,c1通过增加i节点成为c2,再通过一出j节点成为c3】。
Reconfig须要遍历这个DAG,DAG代表了配置的变更过程。每次遍历过程中,DAG都有可能被重复多次更新,由于不同主机的更新。假设超过半数的參与主机没被移除也没有崩溃,就能确保有某条通过DAG路径在全部主机之间都是同样的。有趣的是,尽管主机本身不了解这个共同的路径,但通过遍历全部的路径同样能确保这条共同的路径也被遍历。遍历过程终止于汇聚节点。为了确保重构过程能够终止,必须假设“存在有限数量的又一次配置”。
如今我们回到reconfig的两个阶段。第一阶段的目标是相似于ABD的 获取(Get) 阶段:发现该对象的最新的值-标签对。第二阶段的目标是相似于ABD的Put阶段:传达最新的值-标签对到超过半数的主机。基本的差别是,这两个阶段运行的上下文分别变成了对配置进行增量改动,以及发现其它參与者提交的配置改动。这个过程终于将“引导”出可能的新配置。这个过程是这样实现的:通过遍历DAG的全部可能的路径-也就是配置-从而保证共同路径也被遍历,从而获得终于的新配置。
最后,我们再讨论下read-write操作。Read的实现和reconfig基本同样,不同的地方是:(a)配置更改的集合是空的,(b)所发现的值返回给client。Write也相似reconfig,差异是:(a)变更集是空的,(B)一个新的,更高的标签在第一个阶段的完毕被产生,(c)新的标记值对在第二阶段传播。请注意,读写操作的配置更改的集合是空的,但两个操作都能够发现其它地方提交的变化,并帮助引导配置的改动。如reconfig操作一样,超过半数节点保持稳定工作保证协议能能顺利运行,有限的重构保证操作能正确终结。
值得重申的是Dyna Store的实现不包括关于重构的获得一致的协议。还有一方面,向配置中增加和删除和单个节点,可能导致较大的开销,与之相比,直接用一个完整的配置替换原有配置性能可能更高。因此,read和write操作的延迟更加依赖重构的速度(我们以后将在讨论dynadisk时具体讨论)。最后,为了保证终止,dynastore假设的又一次配置是有限的并终于会停止。兰博是支持多读多写对象的动态存储服务24;Rambo是“基本对象的可重构原子内存”的缩写 【Reconfigurable Atomic Memory for Basic Objects】。该算法使用的配置由一组的副本主机加一个定义在这些主机上Quorum系统组成,Rambo通过替换配置来实现重构。值得注意的是,不论什么quorum配置能够在不论什么时间安装,不同的quroum配置不须要有非空交集。该算法保证了在全部运行的原子性。
没有重构时,算法相似于ABD 算法3(Lynch and Shvartsman32):每两个阶段都会与当前配置中一个完整的quorum进行交互。新的參与者通过与至少一个现有的參与者进行消息握手(不须要又一次配置)。不论什么參与者可能会在不论什么时间崩溃。为使服务的长期运行,quorum能够又一次配置。又一次配置与读写操作并行进行,并不会直接影响这些操作。此外,多个重构过程可能同一时候进行。重构涉及两个不相关的协议:用于引入和更新新的配置的组件叫做Recon,回收废弃的配置的组件叫做垃圾处理。
具体来说,每一个參与者都保持一个配置地图,或CMAP,存储的配置序列,在节点i,cmapi(k)表示他的第k个配置。
Recon不断提出的新配置,旧的配置又被垃圾回收,这使得序列不断演变。不同參与者CMAP中的内容可能不同,可是Recon始终发出唯一的新配置K,该配置被存储在每一个cmapi(K)。这是这样做到的,在c = cmapi(K–1)这个配置中的不论什么节点i能够在不论什么时间提出了一个新的配置。不同的配置建议通过运行c成员间的共识以达成和解(在这里,共识能够通过使用某个版本号paxos来实现29)。
尽管取得共识的过程可能是缓慢的,在某些情况下,甚至有可能不会终止,可是这不延迟的读写操作(仅仅需保证在操作过程中中至少一个quorum是完整的)。注意该结构的成员可能或可能不知道对象的最新值。升级协议负责垃圾收集旧的配置以及传播最新的对象信息。在这里,一个两阶阶段算法首先通知每一个旧配置中的某个quorum有新的配置,然后获取对象的最新值并广播到新配置中的quorum里,并删除过时的配置。
參与者的cmap中可能拥有多个活动配置(尚未被垃圾收集的),假设配置发生的太快,或假设配置升级滞后。在这样的情况下,读写操作的行为例如以下。第一阶段从活动配置中的quorums收集的信息;第二阶段向活动配置中的quorum广播信息。请注意,在每一个阶段,新的配置可能会被发现的。为了解决问题,每一阶段都是由一个涉及每一个活动配置的定点条件而终止。
存储器存取操作从配置解耦使得读写操作一定会终止,即使Recon的过程可能非常缓慢:由于其使用的共识。重构本身涉及到两个独立的活动:通过共识产生的一致的配置序列,然后升级过程最后完毕重构。在某些情况下整合这两种活动,可能是有利于提高性能的,比如,RDS服务.11
最后,Rambo 能够视为改进和优化的基础框架,当中有的改进已经有原型系统实现,比如Georgiou et al.20,接下来我们描写叙述了一个对兰博架构的改造:移动Ad Hoc网络。
所谓焦点(Focal point)指地理上的区域,在这个区域中移动节点(设备)经常产生聚集。焦点可能是一个路口,观景台,或沙漠中的绿洲。在焦点附近的移动节点共同组成一个固定的虚拟对象,称为焦点对象(focal point object)。每一个focal point均支持本地广播服务,LBCAST,该协议能提供可靠的全序广播(totally ordered broadcast)。LBCAST用来实现一种复制状态机,这样的机制能容忍的移动节点增加和离开。假设全部移动节点都离开焦点,焦点对象将失效。
其次,该方法在焦点上定义了一组quorum系统。每一个quorum系统涉及两个集合,称为get-quorum和put-quorums,每一个get-quorum都和put-quorum有交集。quorums使得焦点能容忍有限数量的故障节点。由于性能的原因,或由于移动节点周期性的迁移,能够使用不同的的quorum系统。
为了促进焦点对象(focal point objects)通信,GeoQuorums假定 GeoCast 服务(如在Imielinski26中一样) 能可靠的使消息传递到一个焦点(focal point)的地理区域。使用此设定,你能够使用兰博框架作为原子存储器系统的顶层,而是用focal point 作为副本主机。出于简单性和效率的考虑,GeoQuorums的方法须要做做额外的改动。第一是怎样处理又一次配置,第二怎样影响读写操作的处理。 不管底层的分布式平台产生怎样的扰动,动态原子性存储服务都须要提供数据的一致性和可用性。GeoQuorums第一次引入了一种不依赖共识的又一次配置。该算法实如今有限数量的预定配置之间的又一次配置.算法使用相似Rambo升级协议(update protocal)的两阶段协议代替了共识。在第一阶段,调用者联系全部配置中的完整的get-querum和put-quorum(注意,针对每一个focal point最多仅仅须要一次消息交互,即使配置的数量可能非常大)。接着,在第二阶段,信息被传送到下一个配置中随意一个完整的put-quorum。
GeoQuorums实现了一个改进的读写操作,同意一些操作仅仅在一个阶段完毕。对于写操作,这是通过全球定位系统(GPS)时钟为写入值产生的标签来实现的,这个标签能够将写入排序。这避免了在其它实现中确定最高的标签的阶段,并且写入协议运行仅仅是一个单一的put阶段,该操作与当前的配置中的随意put-quorum进行交互。假设写操作检測到并行重配置操作,将会等待每一个配置的响应(包括至多一次与每一个focal point 的关联)。
一旦写入完毕,标签就被确定。对于读取,该协议涉及一个或两个阶段。第一,获取(get),从一个完整的get-quorum获得标签最大的值;假设一个并行重构操作被监測到,这个阶段也会等待每一个配置中的一个get-quorum进行响应(每一个focal point最多一次消息交换)。一旦获得阶段完毕,并确定了获得最大的标签,读(read)操作将终止。否则,读(read)操作使用放入(put)阶段将最大标签值发送到一些put-quorum。关于已确认标签上的信息会被系统广播以实现单阶段读操作。
使用分离的get-quorum和put-quorum使得我们能够依据系统读写操作的平衡来调优系统。当有很多其它的写操作时,系统能够又一次配置以使用较大的get-quorum和较小的put-quorum,由于write仅仅有使用put-quorums。反之亦然
GeoQuorums使用实时时间戳(由GPS提供)以加快读写操作,同意写和读在一个阶段内完毕。最后,假设有一套固定的focal points限制了系统的可发展性,但同意算法在重构操作时不使用共识。(DSM)精确的一致性保证、对故障的容忍、在动态的环境中工作的能力促使研究人员构建了一些探索性的实现,比方我们已经提到过的,探索性的Rambo变种实现。在这里,我们介绍另外两个实现。第一个是一个从兰博算法思想派生的分布式的磁盘阵列36 。第二个是基于dynastore算法的实现37 。
联合砖块阵列(FAB)36 是由HP实验室开发和评估的存储系统。FAB主要是磁盘存储方案,存储的基本对象的逻辑块(logical blocks)。FAB的实现目标是从工作负载、故障处理、无干扰的请求恢复等各个方面超越传统的主从(Master-Slave)副本分配模式,FAB系统中使用的计算机被称为“砖块”(brick),通常配备普通商用的磁盘和网络接口。为实现分布,FAB将存储切为若干逻辑存储块,使用擦除码(erasure-coding)算法复制每一个逻辑块到bricks子集。该系统是基于多数仲裁(majority quorum【译者:超过半数的提议将成为终于提议】)制度,在确保服务寿命的同一时候,一个重构算法在砖块增加或删除时移动数据。client通过发送一个请求到砖块指定的逻辑块实现读写操作。砖块使用Rambo算法确定存储块被存储在那些砖块上,并进行读写操作,同一时候使用标记-值对实现对写操作的排序。写操作须要两个阶段完毕,读操作须要一个或者两个阶段:当全部砖块返回的值标签都同样,仅仅需一个阶段就能完毕读操作。为了提高效率reader向已激活的空暇砖块请求存储块,仅仅向quorum中的其它成员获取tag。
对FAB实现的评估结果表明:Fab性能相似于集中式的解决方式,同一时候能提供连续的服务和高可用性。
Dynadisk 37是用于评估的dynastore算法实现。測试在局域网环境下进行,採用以数据为中心的方法,在副本主机採用被动网络存储设备。
DynaDisk的设计支持在无共识的条件下又一次配置服务,或採用共识进行部分同步。
评估结果表明,在无重构的情况下,两个版本号算法有着相似的读写延迟,当多个重构同一时候发生时,异步的无共识方法的延迟有明显增加。这是由于无共识算法必须检查多种可能的配置,而整合了共识的重构算法通常仅仅须要检查一个全部节点一致认可的配置。在无共识的DynaDisk版本号中,重构延迟有少量下降,当多个重构操作同一时候发生时。在这样的情况下,有共识的DynaDisk须要更长时间来获得共识。我们提出了动态分布式系统中实现自己主动一致的存储服务的几种方法。在这样的系统中參与节点集合的变化可能由于节点故障、自愿退出或计划的节点更新。我们专注于原子一致性,由于这个概念足够直观和自然,它对内包装多个副本,对外提供了如同操作单一副本一样的串行操作。这样的服务更适合构建分布式应用程序,特别是考虑到使用共享内存的编程范式比使用消息传递范式更easy设计分布式算法。
本文中提到的方法仅仅是众多分布式存储服务实现方法的代表。这些方法,每一个都有长处和缺点。比如,基于共识的解决方式,尽管概念上非常简单,但通常在特定的阶段须要协调员的參与【译者:协调以获取共识】,其性能可能会严重依赖于可用的协调员。即使大多数主机无故障,协调员故障时,也会出现大量的延迟。组通信服务(GCS)是构建高可用性低延迟网络中的有效工具,可是当视图(view)发生变化时开销非常高,即使故障的数目较小但持续时间较长。理论上更加优雅的方法,比方dynastore实现增量节点改动、Rambo实现quorum增量替换、GeoQuorums实现focal point,尽管实现更复杂,但具有更大的灵活性,并同意系统进行特定的优化。是否能实现良好的性能,同一时候也取决于部署平台稳定,故障率的假设,以及一些其它因素,比方FAB中容忍性的考量。
不管怎样对副本主机集合进行重构,何时进行重构也是必须解决的挑战。决定权能够被交个单个主机,比如,在随意一个节点增加或退出服务都要求进行重构。尽管在当扰动不多且副本集合较小时,这样的方法简单有效,但当节点不断增加和离开服务时,这样的方法可能会造成不必要的开销,即使一些核心的主机是稳定的足以提供良好的服务。还有一种方法是把决策何时又一次配置的权利交给还有一个分布式服务,通过观察和推理性预判,找到重构的最佳时机。这是一个更复杂的解决方式,但它具有提供优质的服务的潜力。另外,还能够考虑选择一组合适的主机。系统并不须要同意每一个希望成为复制主机的节点的申请。在这里,决定何时又一次配置的外部服务,同一时候也能够用来选择设置节点的目标。请注意,目标集的不要求共识,全部的存储服务都能够处理多个目标集同一时候被提交的的情况。不管副本主机故障的幅度和频率,动态原子共享内存服务都须要保证全部运行的一致性。可是读写操作是否能终止,就需參考故障的条件了。对于静态的系统,一般来说这个限制非常easy描写叙述:在这里,主机的不论什么少数子集都是是同意失败。动态系统的故障模式的约束更加复杂,取决于具体的算法的方法;读者能够參考引用的文章以了解详情。
随着云服务的出现,分布式存储服务将继续吸引人们的注意。技术挑战和性能方面的开销,造成了现有的分布式存储解决方式回避原子一致性保证。商业解决方式,如谷歌的文件系统(GFS22 ),亚马逊的Dynamo15 ,和facebook的Cassandra,28 提供直观性和保证性稍弱的服务。可是在本问中讨论的概念也得到了一些实际系统的回应。比如,共识技术在GFS22 中使用,以保证系统的正确配置,正如在Rambo中实现的一样;Spanner13 中的全球时间用,原理相似GeoQuorums;Dynamo15 的副本訪问协议,採用了quorum,正如我们在本文中给出的一样。这些样例为我们追寻动态系统中的数据一致性算法提供了动力。
一致性存储系统一直是活跃的研究领域和开发领域,有充分的理由相信,一旦出现具有优越的容错性,同一时候又具备高性能的动态存储系统,将在构建复杂的分布式应用程序中发挥关键的数据。分布式应用程序对一致性和高性能的需求将不断催生对原子的读/写存储器需求。转载于:https://www.cnblogs.com/bhlsheji/p/4004860.html