对称性:每个Dynamo节点应该与它的对等节点(peers)有一样的责任;不应该存在有区别的节点或采取特殊的角色或额外的责任的节。根据我们的经验,对称性(symmetry)简化了系统的配置和维护。
去中心化:是对对称性的延伸,设计应采用有利于去中心化而不是集中控制的技术。在过去,集中控制的设计造成系统中断(outages),而本目标是尽可能避免它。这最终造就一个更简单,更具扩展性,更可用的系统。
异质性:系统必须能够利用异质性的基础设施运行。例如,负载的分配必须与各个独立的服务器的能力成比例。这样就可以一次只增加一个高处理能力的节点,而无需一次升级所有的主机。
3 相关工作
3.1点对点系统
已经有几个点对点(P2P)系统研究过数据存储和分配的问题。如第一代P2P系统Freenet和Gnutella,被主要用作文件共享系统。这些都是由链路任意建立的非结构化P2P的网络的例子。在这些网络中,通常是充斥着通过网络的搜索查询以找到尽可能多地共享数据的对等节点。P2P系统演进到下一代是广泛被称为结构化P2P。这些网络采用了全局一致的协议,以确保任何节点都可以有效率地传送一个搜索查询到那些需要数据的节点。系统,如Pastry[16]和Chord[20]使用路由机制,以确保查询可以在有限的跳数(hops)内得到回答。为了减少多跳路由引入的额外延时,有些P2P系统(例如,[14])采用O(1)路由,每个节点保持足够的路由信息,以便它可以在常数跳数下从本地路由请求(到要访问的数据项)到适当的节点。
其他的存储系统,如Oceanstore[9]和PAST[17]是建立在这些交错的路由基础之上的。Oceanstore提供了一个全局性的,事务性,持久性存储服务,支持对广阔的(widely)复制的数据进行序列化更新。为允许并发更新的同时避免与广域锁定(wide-area locking)固有的许多问题,它使用了一个协调冲突的更新模型。[21]介绍了在协调冲突,以减少交易中止数量。Oceanstore协调冲突的方式是:通过处理一系列的更新,为他们选择一个最终的顺序,然后利用这个顺序原子地进行更新。它是为数据被复制到不受信任的环境的基础设施之上而建立。相比之下,PAST提供了一个基于Pastry和不可改变的对象的简单的抽象层。它假定应用程序可以在它之上建立必要的存储的语义(如可变文件)。
3.2分布式文件系统和数据库
出于对性能,可用性和耐用性考虑,数据分发已被文件系统和数据库系统的社区广泛研究。对比于P2P存储系统的只支持平展的命名空间,分布式文件系统通常支持分层的命名空间。系统象Ficus[15]和Coda[19]其文件复制是以牺牲一致性为代价而达到高可用性。更新冲突管理通常使用专门的协调冲突程序。Farsite系统[1]是一个分布式文件系统,不使用任何类似NFS的中心服务器。Farsite使用复制来实现高可用性和可扩展性。谷歌文件系统[6]是另一个分布式文件系统用来承载谷歌的内部应用程序的状态。GFS使用简单的设计并采用单一的中心(master)服务器管理整个元数据,并且将数据被分成块存储在chunkservers上。Bayou是一个分布式关系数据库系统允许断开(disconnected)操作,并提供最终的数据一致性[21]。
在这些系统中,Bayou,Coda和Ficus允许断开操作和有从如网络分裂和中断的问题中复原的弹性。这些系统的不同之处在于协调冲突程序。例如,Coda和Ficus执行系统级协调冲突方案,Bayou允许应用程序级的解决方案。不过,所有这些都保证最终一致性。类似这些系统,Dynamo允许甚至在网络被分裂(partition - network partition, which is a break in the network that prevents one machine in one data center from interacting directly with another machine in other data center)的情况下继续进行读,写操作,以及使用不同的机制来协调有冲突的更新操作。分布式块存储系统,像FAB[18]将大对象分成较小的块,并以高度可用的方式存储。相对于这些系统中,一个key-value存储在这种情况下更合适,因为:(a)它就是为了存放相对小的物体(大小<1M)和 (b)key-value存储是以每个应用更容易配置为基础的。Antiquity是一个广域分布式存储系统,专为处理多种服务器故障[23]。它使用一个安全的日志来保持数据的完整性,复制日志到多个服务器以达到耐久性,并使用Byzantine容错协议来保证数据的一致性。相对于antiquity,Dynamo不太注重数据完整性和安全问题,并为一个可信赖的环境而建立的。BigTable是一个管理结构化数据的分布式存储系统。它保留着稀疏的,多维的有序映射,并允许应用程序使用多个属性访问他们的数据[2]。相对于Bigtable中,Dynamo的目标应用程序只需要key/value并主要关注高可用性,甚至在网络分裂或服务器故障时,更新操作都不会被拒绝。
传统备份(replicated)关系数据库系统强调保证复制数据的一致性。虽然强一致性给应用编写者提供了一个更方便的应用程序编程模型,但这些系统都只有有限的可伸缩性和可用性[7]。这些系统不能处理网络分裂(partition),因为它们通常提供强的一致性保证。
3.3讨论
与上述去中心化的存储系统相比,Dynamo有着不同的目标需求:首先,Dynamo主要是针对应用程序需要一个“永远可写”数据存储,不会由于故障或并发写入而导致更新操作被拒绝。这是许多Amazon应用的关键要求。其次,如前所述,Dynamo是建立在一个所有节点被认为是值得信赖的单个管理域的基础设施之上。第三,使用Dynamo的应用程序不需要支持分层命名空间(许多文件系统采用的规范)或复杂的(由传统的数据库支持)关系模式的支持。第四,Dynamo是为延时敏感应用程序设计的,需要至少99.9%的读取和写入操作必须在几百毫秒内完成。为了满足这些严格的延时要求,这促使我们必须避免通过多个节点路由请求(这是被多个分布式哈希系统如Chord和Pastry采用典型的设计)。这是因为多跳路由将增加响应时间的可变性,从而导致百分较高的延时的增加。Dynamo可以被定性为零跳(zero-hop)的DHT,每个节点维护足够的路由信息从而直接从本地将请求路由到相应的节点。
4系统架构
一个操作在生产环境里的存储系统的架构是复杂的。除了实际的数据持久化组件,系统需要有负载平衡,成员(membership)和故障检测,故障恢复,副本同步,过载处理,状态转移,并发性和工作调度,请求marshaling,请求路由,系统监控和报警,以及配置管理等可扩展的且强大的解决方案。描述解决方案的每一个细节是不可能的,因此本文的重点是核心技术在分布式系统中使用Dynamo:划分(partitioning),复制(replication),版本(versioning),会员(membership),故障处理(failure handling)和伸缩性(scaling)。表1给出了简要的Dynamo使用的技术清单和各自的优势。
表1:Dynamo使用的技术概要和其优势。
4.1系统接口
Dynamo通过一个简单的接口将对象与key关联,它暴露了两个操作:get()和put()。get(key)操作在存储系统中定位与key关联的对象副本,并返回一个对象或一个包含冲突的版本和对应的上下文对象列表。put(key,context,object)操作基于关联的key决定将对象的副本放在哪,并将副本写入到磁盘。该context包含对象的系统元数据并对于调用者是不透明的(opaque),并且包括如对象的版本信息。上下文信息是与对象一起存储,以便系统可以验证请求中提供的上下文的有效性。
Dynamo将调用者提供的key和对象当成一个不透明的字节数组。它使用MD5对key进行Hash以产生一个128位的标识符,它是用来确定负责(responsible for)那个key的存储节点。
4.2划分算法
Dynamo的关键设计要求之一是必须增量可扩展性。这就需要一个机制来将数据动态划分到系统中的节点(即存储主机)上去。Dynamo的分区方案依赖于一致哈希将负载分发到多个存储主机。在一致的哈希中[10],一个哈希函数的输出范围被视为一个固定的圆形空间或“环”(即最大的哈希值绕到(wrap)最小的哈希值)。系统中的每个节点被分配了这个空间中的一个随机值,它代表着它的在环上的“位置”。每个由key标识的数据项通过计算数据项的key的hash值来产生其在环上的位置。然后沿顺时针方向找到第一个其位置比计算的数据项的位置大的节点。因此,每个节点变成了环上的一个负责它自己与它的前身节点间的区域(region)。一致性哈希的主要优点是节点的进进出出(departure or arrival)只影响其最直接的邻居,而对其他节点没影响。
这对基本的一致性哈希算法提出了一些挑战。首先,每个环上的任意位置的节点分配导致非均匀的数据和负荷分布。二,基本算法无视于节点的性能的异质性。为了解决这些问题,Dynamo采用了一致的哈希(类似于[10,20]中使用的)的变体:每个节点被分配到环多点而不是映射到环上的一个单点。为此,Dynamo使用了“虚拟节点”的概念。系统中一个虚拟节点看起来像单个节点,但每个节点可对多个虚拟节点负责。实际上,当一个新的节点添加到系统中,它被分配环上的多个位置(以下简称“标记” Token )。对Dynamo的划分方案进一步细化在第6部分讨论。
使用虚拟节点具有以下优点:
如果一个节点不可用(由于故障或日常维护),这个节点处理的负载将均匀地分散在剩余的可用节点。当一个节点再次可用,或一个新的节点添加到系统中,新的可用节点接受来自其他可用的每个节点的负载量大致相当。一个节点负责的虚拟节点的数目可以根据其处理能力来决定,顾及到物理基础设施的异质性。
4.3复制
为了实现高可用性和耐用性,Dynamo将数据复制到多台主机上。每个数据项被复制到N台主机,其中N是“每实例”(“per-instance)的配置参数。每个键,K,被分配到一个协调器(coordinator)节点(在上一节所述)。协调器节点掌控其负责范围内的复制数据项。除了在本地存储其范围内的每个key外,协调器节点复制这些key到环上顺时针方向的N-1后继节点。这样的结果是,系统中每个节点负责环上的从其自己到第N个前继节点间的一段区域。在图2中,节点B除了在本地存储键K外,在节点C和D处复制键K。节点D将存储落在范围(A,B],(B,C]和(C,D]上的所有键。