BigTable:结构化数据的分布式存储系统

摘要

Bigtable是一个用于管理结构化数据的分布式存储系统,旨在扩展到非常大的规模:数千个商用服务器上的数PB数据。Google的许多项目都在Bigtable中存储数据,包括网络索引,Google Earth和Google Finance。这些应用对Bigtable提出了非常不同的要求,包括数据大小(从URL到网页到卫星图像)和延迟要求(从后端批处理到实时数据服务)。尽管有这些不同的需求,但Bigtable已成功为所有这些Google产品提供灵活、高性能的解决方案。在本文中,我们描述了Bigtable提供的简单数据模型,它为客户提供了对数据布局和格式的动态控制,并描述了Bigtable的设计和实现。

1. 简介

在过去两年半的时间里,我们设计、实施并部署了一个叫Bigtable的分布式存储系统,用于管理Google的结构化数据。Bigtable旨在可靠地扩展到数PB的数据和数千台计算机。Bigtable实现了多个目标:广泛的适用性、可扩展性、高性能和高可用性。Bigtable被超过60个Google产品和项目使用,包括Google Analytics、Google Finance、Orkut、Personalized
Search、Writely和Google Earth。这些产品使用Bigtable来处理各种要求苛刻的工作,从面向吞吐量的批处理作业到对延迟敏感的数据服务,再到终端用户。这些产品使用的Bigtable集群涵盖了从少量到数千台服务器的各种配置,并可存储高达数百TB的数据。

在很多方面,Bigtable类似于数据库:它与数据库共享许多实现策略。并行数据库[14]和内存数据库[13]已经实现了可扩展性和高性能,但Bigtable提供了与这些系统不同的接口。Bigtable不支持完整的关系数据模型; 相反,它为客户提供了一个简单的数据模型,支持对数据布局和格式的动态控制,并允许客户端推断数据在底层存储中的位置属性。使用可以是任意字符串的行名和列名来索引数据。Bigtable也将数据视为未解释的字符串,尽管客户端经常将各种形式的结构化和半结构化数据序列化为这些字符串。客户端可以通过在模式中仔细选择来控制数据的位置。最后,Bigtable模式参数允许客户端动态控制是从内存还是从磁盘提供数据。

第2节更详细地描述了数据模型,第3节提供了客户端API的概述。第4节简要介绍了Bigtable所依赖的底层Google基础设施。第5节描述了Bigtable实现的基本原理,第6节描述了我们为提高Bigtable性能所做的一些改进。第7节提供了Bigtable的性能测试。我们在第8节中描述了几个关于如何在Google中使用Bigtable的示例,并在第9节中讨论了我们设计和支持Bigtable时学到的一些经验教训。最后,第10节描述了相关工作,第11节介绍了我们的总结。

2. 数据模型

Bigtable是一个稀疏的、分布式的、持久化的多维有序映射。映射由行键、列键和时间戳索引; 映射中的每个值都是未解释的字节数组。

(row:string, column:string, time:int64) -> string

图1:存储Web页面的示例表的一部分。行名称是反转的URL。内容列族包含页面内容,锚列族包含引用页面的任何锚点的文本。 CNN的主页由Sports Illustrated和MY-look主页引用,因此该行包含名为anchor:cnnsi.com和anchor:my.look.ca的列。每个锚单元有一个版本; 内容列有三个版本,时间戳分别为t3,t5和t6。
在研究了类Bigtable系统的各种潜在用途后,我们确定了这个数据模型。作为推动我们的一些设计决策的一个具体例子:假设我们想要保留会被许多不同项目使用的大量网页和相关信息的副本; 让我们将这个特定的表称为Webtable。在Webtable中,我们将URL用作行键,将网页的各个方面用作列名,并将网页的内容存储在contents列中:列在抓取网页时的时间戳下,如图1所示。

2.1 行

表中的行键是任意字符串(当前最大为64KB,但对于大多数用户来说,10-100字节是典型的大小)。单个行键下的每次数据读取或写入都是原子的(无论行中读取或写入的不同列的数量如何),这一设计决策使客户端更容易在出现并发更新到同一行时推断系统的行为。

Bigtable维护按行键的字典顺序排列的数据。表的行范围是动态分区的。每个行范围称为一个分片,它是分配和负载均衡的单位。结果,小的行范围的读取是高效的,并且通常只需要与少量机器通信。客户端可以通过选择行键来利用此特性,以便它们获得数据访问的好的定位。例如,在Webtable中,通过反转的URL的主机名组成,将同一域名中的页面分组在一起成为连续的行。例如,我们会在键com.google.maps/index.html下存储maps.google.com/index.html的数据。将来自同一域名的页面存储在彼此附近使得一些主机和域名分析更高效。

2.2 列族

列键被分组后的集合称为称为列族,这构成了访问控制的基本单元。存储在列族中的所有数据通常具有相同的类型(我们将同一列族中的数据压缩在一起)。必须先创建列族,然后才能将数据存储在该族中的任何列键下; 在创建列族之后,可以使用列族中的任何列键。我们的意图是表中不同列族的数量很小(最多数百个),并且族在运行期间很少发生变化。相反,表可能具有无限数量的列。

使用以下语法命名列键:family:qualifier。列族名称必须是可打印的,但限定符可以是任意字符串。Webtable的示例列族是language,它存储编写网页的语言。我们在language列族中只使用一个列键,它存储每个网页的语言ID。该表的另一个有用的列族是anchor; 此列族中的每个列键代表一个锚点,如图1所示。限定符是引用站点的名称; 单元内容是链接文本。

访问控制以及磁盘和内存统计都在列族级别执行。在我们的Webtable示例中,这些控制允许我们管理几种不同类型的应用:一些用于添加新的基础数据,一些用于读取基础数据并创建派生列族,还有一些仅允许查看现有数据(出于隐私原因甚至可能不会查看所有现有列族)。

2.3 时间戳

Bigtable中的每个单元都可以包含相同数据的多个版本; 这些版本由时间戳索引。Bigtable时间戳是64位整数。它们可以由Bigtable分配,在这种情况下,它们以微秒表示“实时”,或由客户端应用显式分配。需要避免冲突的应用必须自己生成唯一的时间戳。以时间戳递减的顺序存储单元的不同版本,以便可以首先读取最新版本。

为了方便版本化数据的管理,我们支持两个列族设置,告诉Bigtable自动垃圾收集单元版本。客户端可以指定仅保留单元的最后n个版本,或者仅保留足够新的版本(例如,仅保留在过去七天中写入的值)。

在我们的Webtable示例中,我们将存储在contents列已爬取网页的时间戳设置为:实际爬取这些页面版本的时间。上面描述的垃圾收集机制让我们能只保留每个页面的最新三个版本。

3. API

Bigtable API提供了创建和删除表和列族的功能。它还提供用于更改集群、表和列族元数据的功能,例如访问控制权限。

客户端应用程序可以在Bigtable中写入或删除值,从单个行中查找值,或迭代表中数据的子集。图2显示了使用RowMutation抽象来执行一系列更新的C ++代码。(不相关的细节被省略以保持示例简短。)调用Apply对Webtable执行原子变更:它向www.cnn.com添加一个锚并删除一个不同的锚。

图2:写入Bigtable。
图3显示了使用Scanner抽象迭代特定行中所有锚点的C ++代码。客户端可以迭代多个列族,并且有几种机制可以生成限制的扫描行、列和时间戳。例如,我们可以将上面的扫描限制为仅生成其列与正则表达式锚点:*.cnn.com匹配的锚点,或者仅生成其时间戳落在当前时间的十天内的锚点。

图3:从Bigtable读取。
Bigtable支持其他一些功能,允许用户以更复杂的方式操作数据。首先,Bigtable支持单行事务,可用于对存储在单行键下的数据执行原子读-修改-写序列操作。Bigtable目前不支持跨行的常规事务,但它提供了一个接口,用于在客户端上批量跨行写入。其次,Bigtable允许将单元用作整数计数器。最后,Bigtable支持在服务器的地址空间中执行客户端提供的脚本。这些脚本是用Google开发的一种语言编写的,用于处理称为Sawzall的数据[28]。目前,我们基于Sawzall的API不允许客户端脚本写回Bigtable,但它允许各种形式的数据转换,基于任意表达式的过滤以及通过各种运算符进行汇总。

Bigtable可以与MapReduce[12]一起使用,MapReduce是一个在Google中用于运行开发的大规模并行计算的框架。我们编写了一组包装器,允许Bigtable既可以用作输入源,也可以用作MapReduce作业的输出目标。

4. 构成模块

Bigtable建立在其他几个Google基础设施上。Bigtable使用分布式Google文件系统(GFS)[17]来存储日志和数据文件。Bigtable集群通常在运行有各种其他分布式应用的共享计算机池中运行,并且Bigtable进程通常与来自其他应用的进程共享相同的计算机。Bigtable依赖于集群管理系统来调度作业、管理共享机器上的资源、处理机器故障以及监视机器状态。

Google SSTable文件格式在内部用于存储Bigtable数据。SSTable提供从键到值的持久的、有序不可变的映射,其中键和值都是任意字节串。提供了查找与指定键相关联的值的操作,并迭代指定键范围内的所有键/值对。在内部,每个SSTable都包含一系列块(通常每个块的大小为64KB,但这是可配置的)。块索引(存储在SSTable的末尾)用于定位块; 打开SSTable时,索引将加载到内存中。可以使用单个磁盘搜索执行查找:我们首先通过在内存索引中执行二分查找,然后从磁盘读取相应的块来找到适当的块。可选地,SSTable可以完全映射到内存中,这允许我们在不接触磁盘的情况下执行查找和扫描。

Bigtable依赖于一种名为Chubby[8]的高可用和持久化的分布式锁服务。Chubby服务由五个活跃副本组成,其中一个被选为主服务器并主动服务请求。当大多数副本正在运行并且可以相互通信时,该服务是活着的。Chubby使用Paxos算法[9,23]来保证其副本在失败时保持一致。Chubby提供了一个由目录和小文件组成的命名空间。每个目录或文件都可以用作锁,对文件的读写是原子的。Chubby客户端库提供了Chubby文件的一致缓存。每个Chubby客户端都使用Chubby服务维护会话。如果客户端会话无法在租约到期时间内续订其会话租约,则会话过期。当客户端的会话到期时,它会丢失所有的锁和打开的句柄。Chubby客户端还可以在Chubby文件和目录上注册回调,以通知更改或会话到期。

Bigtable在各种任务中使用Chubby:确保任何时候最多只有一个活跃的主服务器; 存储Bigtable数据的引导位置(参见5.1节); 发现片服务器并最终确定片服务器死亡(参见第5.2节); 存储Bigtable元信息(每个表的列族信息); 并存储访问控制列表。如果Chubby长时间不可用,Bigtable将无法使用。我们最近在跨越11个Chubby实例的14个Bigtable集群中测试了这种影响。由于Chubby不可用(由Chubby停机或网络问题引起)导致Bigtable中存储的某些数据无法使用的Bigtable服务小时数的平均百分比为0.0047%。受Chubby不可用性影响最大的单个集群的百分比为0.0326%。

5. 实现

Bigtable实现有三个主要组成:链接到每个客户端的库,一个主服务器和许多片服务器。可以从集群中动态添加(或删除)片服务器,以适应工作负载的变化。

主服务器负责将分片分配给片服务器,检测片服务器的添加和过期、均衡片服务器负载以及GFS中文件的垃圾收集。此外,它还处理模式更改,例如表和列族创建。

每个片服务器管理一组分片(通常我们每个片服务器有10到1000个分片)。片服务器处理对已加载的分片的读写请求,并且还会拆分已经过大的分片。与许多单主分布式存储系统[17,21]一样,客户端数据不会通过主服务器传输:客户端直接与片服务器通信以进行读写。由于Bigtable客户端不依赖主服务器来获取分片位置信息,因此大多数客户端从不与主服务器通信。因此,主服务器的负载实际很轻量。

Bigtable集群存储了许多表。每个表包含一组分片,每个分片包含与行范围相关的所有数据。最初,每个表只包含一个分片。随着表的增长,它会自动拆分为多个分片,默认情况下每个大小约为100-200 MB。

5.1 分片位置

我们使用类似于B+ tree [10]的三级层次结构来存储分片位置信息(图4)。

图4:分片位置层次结构。
第一层是存储在Chubby中的文件,其中包含根分片的位置。根分片中的特殊METADATA表包含所有分片的位置。每个METADATA分片都包含一组用户分片的位置。根分片只是METADATA表中的第一个分片,但是经过特殊处理 - 它永远不会拆分 - 以确保分片位置层次结构不超过三个层级。

METADATA表将分片的位置存储在行键下,该行键是片的表标识符及其结束行的编码。每个METADATA行在内存中的存储大约为1KB的数据。由于适度的128 MB METADATA分片的限制,我们的三级定位方案足以定位2^34个分片(或128 MB分片中2^61字节)。

客户端库缓存分片位置。如果客户端不知道分片的位置,或者它发现缓存的位置信息不正确,则它会沿分片位置层次结构递归地向上移动。如果客户端的缓存为空,则位置算法需要三次网络往返,包括从Chubby读取一次。如果客户端的缓存是陈旧的,则位置算法可能需要六次往返,因为只有在未命中时才会发现过时的缓存条目(假设METADATA分片不会频繁移动)。由于分片位置存储在内存中,因此不需要访问GFS,但我们通过使用客户端库预拉取分片位置来进一步降低此成本:只要读取METADATA表,它就会读取多个分片的元数据。

我们还将辅助信息存储在METADATA表中,包括与每个分片相关的所有事件的日志(例如服务器开始提供服务时间)。此信息有助于调试和性能分析。

5.2 片分配

每个分片一次分配给一个片服务器。主服务器会跟踪活着的片服务器的集合,以及当前的分片到片服务器的分配,包括哪些分片未分配。如果分片未分配,并且一个片服务器具有足够的空间给该分片,则主服务器会通过向片服务器发送分片加载的请求来分配分片。

Bigtable使用Chubby来跟踪片服务器。当片服务器启动时,它会创建并获取对特定Chubby目录中唯一命名文件的独占锁。主服务器监控此目录(服务器目录)以发现片服务器。如果一个片服务器失去其独占锁,它将停止为其分片提供服务:例如,由于网络隔离导致服务器丢失其Chubby会话。(Chubby提供了一种有效的机制,允许片服务器检查它是否仍然保持锁而不会产生网络流量。)只要文件仍然存在,片服务器就会尝试重新获取其文件的独占锁。如果该文件不再存在,则片服务器将永远无法再次服务,因此它会自行终止。每当片服务器终止时(例如,因为集群管理系统正在从集群中移除片服务器的机器),它就会尝试释放其锁定,以便主服务器更快地重新分配其分片。

主服务器负责检测片服务器何时不再服务其分片,以及尽快重新分配这些分片。要检测片服务器何时不再为其分片提供服务,主服务器会定期向每个片服务器询问其锁状态。如果片服务器报告它已失去锁定,或者主服务器在最近几次尝试期间无法访问服务器,则主服务器会尝试获取该服务器文件的独占锁。如果主服务器能够获得锁,则Chubby处于活跃状态且片服务器已经死机或无法访问Chubby,因此主服务器确保片服务器永远不会通过删除其服务器文件再次服务。一旦服务器文件被删除后,主服务器可以将之前分配给该服务器的所有分片移动到未分配的分片集合中。为了确保Bigtable集群不容易受到主服务器和Chubby之间的网络问题的影响,如果其Chubby会话到期,主服务器将自行终止。但是,如上所述,主服务器故障不会改变分片到片服务器的分配。

当主服务器被集群管理系统启动时,它需要先获得当前的分片分配,然后才能更改它们。 主服务器在启动时执行以下步骤。(1) 主服务器在Chubby中获取一个唯一的主服务器锁,这会阻止并发的主服务器实例化。(2) 主服务器扫描Chubby中的服务器目录以查找活跃的服务器。(3) 主服务器与每个活跃片服务器通信,以发现已为每个服务器分配了哪些分片。(4) 主服务器扫描METADATA表以获知分片集合。每当此扫描遇到尚未分配的分片时,主服务器会将该分片添加到未分配分片的集合中,这使该分片有资格进行分片分配。

一个复杂的问题是,在分配METADATA分片之前,不能对METADATA表进行扫描。因此,在开始此扫描(步骤4)之前,如果在步骤3中未发现根分片的分配,则主服务器会将根分片添加到未分配的分片集合中。此添加确保将分配根分片。由于根分片包含所有METADATA分片的名称,因此主服务器在扫描根分片后会知道所有分片。

表的现有分片的集合只有在创建或删除表、将两个现有分片合并为一个更大的分片、或者将现有分片拆分为两个较小的分片时才会更改。主服务器能够跟踪这些变化,因为它会启动除最后一项之外的所有变化。分片拆分是特殊处理的,因为它们是由片服务器启动的。片服务器通过在METADATA表中记录新分片的信息来提交拆分。拆分提交后,它会通知主服务器。如果拆分通知丢失(由于片服务器或主服务器已经死亡),主服务器会在请求片服务器加载现在已拆分的分片时检测新分片。片服务器将通知主服务器该拆分,因为它在METADATA表中找到的分片条目将仅指定主机要求加载的一部分分片。

5.3 片服务器

分片的持久状态存储在GFS中,如图5所示。更新被提交到存储重做记录的提交日志中。在这些更新中,最近提交的更新存储在称为memtable的排序缓冲区的内存中; 较旧的更新存储在一系列SSTable中。要恢复分片,片服务器会从METADATA表中读取其元数据。此元数据包含组成分片的SSTable列表和一组重做点,这些重做点是指向可能包含分片数据的任何提交日志的指针。服务器将SSTable的索引读入内存,并通过应用自重做点以来已提交的所有更新来重构memtable。

图5:分片表示
当写操作到达片服务器时,服务器检查它是否格式正确,并且发送者是否有权执行变更。通过从Chubby文件中读取允许的写入器列表来执行授权(这几乎总是命中Chubby客户端缓存)。将有效的变更写入提交日志。分组提交用于提高许多小变更的吞吐量[13,16]。写入提交后,其内容将插入到memtable中。

当读取操作到达片服务器时,类似地会检查其是否格式良好并有适当的授权。在SSTables的列表和memtable的合并视图上执行有效的读操作。由于SSTable和memtable是按字典序排序的数据结构,因此可以有效地形成合并视图。

在拆分和合并分片的同时,可以继续进行读取和写入操作。

5.4 压缩

当写操作执行时,memtable的大小增加。当memtable大小达到阈值时,memtable被冻结,并创建一个新的memtable,冻结的memtable转换为SSTable并写入GFS。这个minor压缩过程有两个目标:它缩小了片服务器的内存使用量,并减少了如果此服务器死机时恢复期间必须从提交日志中读取的数据量。压缩发生时,输入的读写操作可以继续。

每次minor压缩都会创建一个新的SSTable。如果此行为继续未被遏制,则读取操作可能需要合并来自任意数量的SSTable的更新。反之,我们通过在后台定期执行合并压缩来限制此类文件的数量。合并压缩读取一些SSTable和memtable的内容,并写出一个新的SSTable。压缩完成后,可以丢弃输入的SSTable和memtable。

将所有SSTable重写为一个SSTable的合并压缩称为major压缩。非major压缩生成的SSTable可以包含特殊删除条目,这些条目可以抑制仍处于活跃状态的旧SSTable中的已删除数据。另一方面,major压缩产生不包含删除信息或删除数据的SSTable。Bigtable在其所有分片中循环、并定期对其进行major压缩。这些major压缩允许Bigtable回收已删除数据使用的资源,并允许它确保已删除的数据及时从系统中消失,这对于存储敏感数据的服务非常重要。

6. 改进

上一节中描述的实现需要进行一些改进,以实现用户所需的高性能、可用性和可靠性。本节更详细地描述了部分实现,以突出显示这些改进。

6.1 位置分组

客户端可以将多个列族组合到一个位置分组中。为每个分片中的每个位置分组生成单独的SSTable。将通常不一起访问的列族隔离到不同的位置分组中可以实现更高效的读取。例如,Webtable中的页面元数据(例如语言和校验和)可以位于一个位置分组中,并且页面的内容可以位于不同的分组中:想要读取元数据的应用不需要读取所有页面内容。

此外,可以基于每个位置分组指定一些有用的调整参数。例如,可以将位置分组声明到内存中。内存中位置分组的SSTable可以延迟加载到片服务器的内存中。一旦加载后,可以在不访问磁盘的情况下读取属于此位置分组的列族。此功能对于经常访问的小块数据非常有用:我们在内部将它用于METADATA表中的位置列族。

6.2 压缩

客户端可以控制SSTable是否压缩一个位置分组,以及如果是,则使用哪种压缩格式。用户指定的压缩格式应用于每个SSTable块(其大小可通过位置分组的特定调整参数控制)。虽然我们通过单独压缩每个块而损失了一些空间,但我们受益于可以在不解压缩整个文件的情况下读取SSTable的一小部分。许多客户端使用两遍自定义压缩方案。 第一遍使用Bentley和McIlroy的方案[6],它在大窗口中压缩长公共字符串。 第二遍使用快速压缩算法,该算法在数据的小16 KB窗口中查找重复项。两种压缩算法都非常快 - 它们以100-200 MB/s的速度编码,在现代机器上以400-1000 MB/s的速度进行解码。

尽管我们在选择压缩算法时强调速度而不是空间缩减,但这种两遍压缩方案确实出奇的好。例如,在Webtable中,我们使用此压缩方案来存储网页内容。在一个实验中,我们将大量文档存储在压缩的位置分组中。出于实验目的,我们限定每个文档只有一个版本,而不是存储对我们可用的所有版本。该方案实现了空间减少到10:1。这比基于HTML页面典型的Gzip压缩减少到3:1或4:1要好得多,因为Webtable行的布局方式:来自同一个主机的所有页面都彼此靠近存储。这允许Bentley-McIlroy算法识别来自同一主机的页面中的大量共享引用。许多应用(不仅仅是Webtable)选择其行名称,以便类似的数据最终聚集在一起,从而实现非常好的压缩率。当我们在Bigtable中存储相同值的多个版本时,压缩率会更好。

6.3 为读取性能缓存

为了提高读取性能,片服务器使用两级缓存。扫描缓存是一种更高级别的缓存,用于将SSTable接口返回的键值对缓存到片服务器代码中。块缓存是一个较低级别的缓存,用于缓存从GFS读取的SSTables块。扫描缓存对于倾向于重复读取相同数据的应用最有用。块缓存对于倾向于读取与其最近读取的数据接近的数据的应用(例如,顺序读取,或热行内相同位置分组中的不同列的随机读取)非常有用。

6.4 布隆过滤器

如第5.3节所述,读取操作必须从组成分片状态的所有SSTable中读取。如果这些SSTable不在内存中,我们最终可能会进行许多磁盘访问。我们通过允许客户端指定应该为特定位置分组中的SSTable创建的Bloom过滤器[7]来减少访问次数。Bloom过滤器允许我们询问SSTable是否可能包含指定行/列对的任何数据。对于某些应用,用于存储Bloom过滤器的少量片服务器内存大大减少了读取操作所需的磁盘搜索次数。我们对Bloom过滤器的使用也意味着对不存在的行或列的大多数查找不需要接触磁盘。

6.5 提交日志实现

如果我们将每个分片的提交日志保存在单独的日志文件中,则会在GFS中同时写入大量文件。依赖于每个GFS服务器上的基础文件系统实现,这些写入可能导致大量磁盘搜索以写入不同的物理日志文件。此外,每个分片具有单独的日志文件也会降低分组提交优化的效果,因为分组往往会更小。为了解决这些问题,我们将变更添加到每个片服务器的单个提交日志中,在同一物理日志文件[18,20]中混合不同分片的变更。

在正常操作中使用单一日志可提供显著的性能优势,但这会使恢复变得复杂。当片服务器死机时,它所服务的分片将被移动到许多其他片服务器:每台服务器通常会加载少量原服务器的分片。要恢复分片的状态,新的片服务器需要从原片服务器写入的提交日志中重新应用该分片的变更。但是,这些分片的变更混合在同一物理日志文件中。一种方法是每个新的片服务器读取这个完整的提交日志文件,并仅应用它需要恢复的分片所需的条目。但是,在这样的方案下,如果从故障片服务器给100台计算机的每台计算机分配一个分片,那么日志文件将被读取100次(每个服务器一次)。

我们通过首先按照键<table,row name,log sequence number>的顺序对提交日志条目进行排序来避免重复日志读取。在排序的输出中,特定分片的所有变更都是连续的,因此可以通过一次磁盘搜索然后顺序读取来高效读取。为了并行化排序,我们将日志文件分区为64 MB段,并在不同的片服务器上并行对每个段进行排序。此排序过程由主服务器协调,并在片服务器表示需要从某个提交日志文件中恢复变更时启动。

将提交日志写入GFS有时会由于各种原因导致性能问题(例如,GFS服务器计算机涉及写入崩溃中,或者到达特定的三个GFS服务器集合的网络路径正在遭受网络拥塞,或者负载过重)。为了保护GFS延迟峰值变更,每个片服务器实际上有两个日志写入线程,每个线程写入自己的日志文件; 这两个线程同时只有一个在活跃使用中。如果对活跃日志文件的写入性能不佳,则将日志文件写入切换到另一个线程,并且提交日志队列中的变更由新激活的日志写入线程写入。日志条目包含序列号,以允许恢复过程忽略由此日志切换过程产生的重复条目。

6.6 加快分片的恢复速度

如果主服务器将分片从一台片服务器移动到另一台,则源片服务器首先会对该分片进行minor压缩。该压缩减少了片服务器的提交日志中未压缩状态的数量来缩短恢复时间。完成此压缩后,片服务器将停止为该分片提供服务。在实际卸载分片之前,片服务器会执行另一次(通常是非常快速的)minor压缩,以消除在执行第一次minor压缩时到达的片服务器日志中的任何剩余未压缩状态。在完成第二次minor压缩之后,可以将该分片加载到另一台片服务器上,而无需任何日志条目的恢复。

6.7 利用不变性

除了SSTable缓存之外,Bigtable系统的其他各个部分都被简化了,因为我们生成的所有SSTable都是不可变的。例如,从SSTables读取时,我们不需要对访问文件系统同步。因此,可以非常有效地实现对行的并发控制。读取和写入都可访问的唯一可变数据结构是memtable。为了减少读取memtable期间的竞争,我们将memtable的每个行写入进行写时复制并允许读取和写入并行进行。

由于SSTables是不可变的,因此永久删除已删除数据的问题将转换为垃圾收集过时的SSTables。每个分片的SSTable都在METADATA表中注册。主服务器将过时的SSTable利用标记清除垃圾收集[25]从SSTable集合移除,其中METADATA表包含根集合。

最后,SSTables的不变性使我们能够快速拆分分片。我们让子分片共享父分片的SSTables,而不是为每个子分片生成一组新的SSTable。

7. 性能评估

我们搭建了一个带有N台片服务器的Bigtable集群,用于测量Bigtable的性能和可扩展性,因为N是多变的。片服务器配置为使用1 GB内存并写入由1786台机器组成的GFS单元,每台机器具有两个400 GB IDE硬盘驱动。N台客户机生成了用于这些测试的Bigtable负载。(我们使用与片服务器相同数量的客户端来确保客户端永远不会成为瓶颈。)每台机器都有两个双核Opteron 2 GHz芯片,足够的物理内存来容纳所有正在运行的进程的工作集,以及一个千兆比特以太网链路。这些机器被安排在一个两级树形交换网络中,根部有大约100-200 Gbps的总带宽。所有机器都在同一个托管设施中,因此任何两台机器之间的往返时间不到一毫秒。

片服务器和主服务器,测试客户端和GFS服务器都运行在同一组计算机上。每台机器都运行一个GFS服务器。某些计算机还运行片服务器或客户端进程,或者与这些实验同时使用资源池的其他作业的进程。

R是测试中涉及的Bigtable不同行键的数量。选择R以使每个基准测试从每个片服务器读取或写入大约1 GB的数据。

顺序写入基准测试使用名称为0到R-1的行键。行键的这个空间被划分为10N个相等大小的范围。这些范围由中央调度程序分配给N个客户端,一旦客户端处理完成分配给它的前一个范围,就将下一个可用范围分配给该客户端。此动态分配有助于减轻由客户端计算机上运行的其他进程引起的性能变化的影响。我们在每个行键下面写了单个字符串。每个字符串都是随机生成的,因此是不可压缩的。另外,不同行键下的字符串是不同的,因此不可能进行跨行压缩。随机写入基准测试是类似的,除了在写入之前立即对行键进行模数R散列,以便在整个基准测试持续时间内将写入负载大致均匀地分布在整个行空间中。

图6:每秒读/写的1000字节的数量。该表显示了每台片服务器的速率; 该图显示了总速率。
顺序读取基准测试以与顺序写入基准测试完全相同的方式生成行键,但不是在行键下写入,而是读取存储在行键下的字符串(由早期的顺序写入基准测试调用写入)。类似地,随机读取基准测试隐藏了随机写入基准测试的操作。

扫描基准测试与顺序读取基准测试类似,但使用Bigtable API提供的支持以扫描行范围内的所有值。由於单个RPC从片服务器获取大量值,因此使用扫描可减少基准测试执行的RPC数量。随机读取(mem)基准测试类似于随机读取基准测试,但包含有基准测试数据的位置分组被标记在内存中,因此从片服务器的内存中读取数据,而不是需要GFS读取。对于此基准测试,我们将每台片服务器的数据量从1 GB减少到100 MB,以便它可以轻松被放入片服务器可用的内存中。

图6显示了在向Bigtable读取和写入1000字节值时基准测试性能的两个视图。该表显示了每台片服务器每秒的操作数; 该图显示了每秒的总操作数。

7.1 单个片服务器性能

让我们首先考虑一台片服务器的性能。随机读取比所有其他操作慢一个数量级或更多。每次随机读取都涉及通过网络将64 KB SSTable块从GFS传输到片服务器,其中只使用了1000字节的值。片服务器每秒执行大约1200次读取,这转换为从GFS大约75 MB/s的数据读取。由于我们的网络堆栈、SSTable解析和Bigtable代码的开销,这个带宽足以使片服务器CPU饱和,并且几乎足以使我们系统中使用的网络链路饱和。具有此类访问模式的大多数Bigtable应用将块大小减小到较小的值,通常为8KB。

从内存中随机读取要快得多,因为每1000字节的读取从片服务器的本地内存中读取而不从GFS获取大的64 KB块。

随机和顺序写入比随机读取执行得更好,因为每个片服务器将所有输入的写入附加到单个提交日志中,并使用分组提交将这些写入有效地流式传输到GFS。随机写入和顺序写入的性能没有显著差异; 在这两种情况下,对片服务器的所有写入都记录在同一个提交日志中。

顺序读取比随机读取执行得更好,因为从GFS获取的每个64 KB SSTable块都存储在我们的块缓存中,用于为接下来的64个读取请求提供服务。

由于片服务器可以返回大量值以响应单个客户端RPC,因此扫描速度更快,因此RPC开销会在大量值上分摊。

7.2 扩展性

随着我们将系统中的片服务器数量从1增加到500,总体吞吐量急剧增加了一百倍。例如,当片服务器增加500倍,内存中随机读取的性能增加了近300倍。出现这种情况是因为此基准测试的性能瓶颈是单个片服务器CPU。

但是,性能没有线性增加。对于大多数基准测试,从1台到50台片服务器时,每台服务器吞吐量显著下降。这种下降是由多个服务器配置中的负载不平衡引起的,通常是由于其他进程争用CPU和网络。我们的负载均衡算法试图解决这种不平衡问题,但由于两个主要原因无法完成工作:重新均衡会受限于减少分片的移动次数(分片短时间内不可用,当移动它时通常不到一秒钟),随着基准测试的前进,我们的基准测试产生的负载会随之偏移。

随机读取基准测试显示了最差的扩展(服务器数量增加了500倍,总吞吐量增加了100倍)。出现此问题的原因是(如上所述)我们通过网络为每1000字节读取传输一个大的64KB块。这种传输使我们网络中各个共享的1千兆比特链路达到饱和,因此,随着我们增加机器数量,每台服务器吞吐量显著下降。

8. 实际应用

截至2006年8月,共有388个非测试Bigtable集群在各Google机器集群中运行,总计约24500台片服务器。表1显示了每个集群的片服务器的粗略分布。许多这些集群用于开发目的,因此在很长一段时间内处于闲置状态。一组14个繁忙的集群,总计8069个片服务器,每秒的请求总量超过120万,输入的RPC流量约为741 MB/s,输出的RPC流量约为16 GB/s。

表1:Bigtable集群中片服务器数量的分布。
表2提供了有关当前使用的一些表的一些数据。有些表存储提供给用户服务的数据,而有些表存储用于批处理的数据; 这些表在包括总大小、平均单元大小、从内存提供的数据百分比以及表模式的复杂性方面范围很广。在本节的其余部分,我们将简要介绍三个产品团队如何使用Bigtable。

表2:生产用途中几个表的特征。表大小(压缩前测量)和#Cells表示大致尺寸。对于已禁用压缩的表,未给出压缩率。

8.1 Google Analytics

Google Analytics(analytics.google.com)是一项服务,可帮助网站管理员分析其网站上的流量模式。它提供了汇总统计信息,例如每天唯一身份访问者的数量和每个URL每天的网页浏览量,以及网站跟踪报告,例如进行购买的用户百分比,因为他们之前查看过特定网页。

为了启用该服务,网站管理员在其网页中嵌入了一个小型JavaScript程序。每当访问页面时都会调用此程序。它会在Google Analytics中记录有关请求的各种信息,例如用户标识符和有关正在获取的页面的信息。Google Analytics汇总了这些数据,并将其提供给网站管理员。

我们简要介绍Google Analytics使用的两个表。原始点击表(~200 TB)为每个终端用户会话维护一行。行名称是一个元组,包含网站的名称和创建会话的时间。此模式可确保访问同一网站的会话是连续的,并且它们按时间顺序排序。此表压缩到原始大小的14%。

摘要表(~20 TB)包含每个网站的各种预定义摘要。此表是通过定期调度的MapReduce作业从原始点击表生成的。每个MapReduce作业都从原始点击表中提取最近的会话数据。整个系统的吞吐量受到GFS吞吐量的限制。此表压缩到原始大小的29%。

8.2 Google Earth

Google通过基于网络的Google地图界面(maps.google.com)和Google Earth(earth.google.com)顾客客户端软件运营一系列服务,为用户提供访问世界范围地面的高分辨率卫星图像的权限。这些产品允许用户在世界各地进行导航:他们可以在许多不同级别的分辨率下平移、查看和标注卫星图像。该系统使用一个表来预处理数据,使用一组不同的表来提供客户端数据。

预处理管道使用一个表来存储原始图像。在预处理期间,图像被清理并合并到最终的服务数据中。该表包含大约70 TB的数据,因此从磁盘提供服务。图像已经被有效压缩,因此禁用Bigtable压缩。

图像表中的每一行对应一个地理段。命名行以确保相邻的地理段彼此靠近存储。该表包含一个列族,用于跟踪每个段的数据源。此列族具有大量列:基本上每个原始数据一列。由于每个段仅由几个图像构成,因此该列族非常稀疏。

预处理管道在很大程度上依赖于Bigtable上的MapReduce来转换数据。在某些MapReduce作业期间,整个系统的每个片服务器处理超过1 MB/s的数据。

服务系统使用一个表来索引存储在GFS中的数据。此表相对较小(~500 GB),但每个数据中心每秒必须提供数万个低延迟的查询。因此,该表托管在数百台片服务器上,并在内存中容纳列族。

8.3 Personalized Search

Personalized Search(www.google.com/psearch)是一项选择性服务,可记录用户在各种Google业务上的查询和点击,例如网络搜索、图片和新闻。用户可以浏览他们的搜索历史记录以重新访问他们的旧查询和点击,他们可以根据他们历史的Google使用模式请求个性化搜索结果。

Personalized Search将每个用户的数据存储在Bigtable中。每个用户都有一个唯一的userid,并被分配一个由该userid命名的行。所有用户操作都存储在表中。为每种类型的操作保留单独的列族(例如,存在存储所有Web查询的列族)。每个数据元素使用Bigtable时间戳作为对应用户操作发生的时间。Personalized Search使用Bigtable上的MapReduce生成用户画像。这些用户画像用于个性化实时搜索结果。

Personalized Search数据在多个Bigtable集群中进行复制,以提高可用性并减少因与客户端的距离而导致的延迟。Personalized Search团队最初在Bigtable之上构建了一个客户端复制机制,并确保了所有副本的最终一致性。当前系统现在使用内置于服务器中的复制子系统。

Personalized Search存储系统的设计允许其他团队在其自己的列中添加新的每个用户的信息,并且该系统现在被许多其他需要存储每个用户的配置选项和设置的Google业务使用。在许多团队之间共享一个表导致了非常多的列族。为了帮助支持共享,我们为Bigtable添加了一个简单的配额机制,以限制共享表中任何特定客户端的存储消耗; 此机制在使用此系统的各个产品团队之间为每个用户的信息存储提供了一些隔离。

9. 教训

在设计、实施、维护和支持Bigtable的过程中,我们获得了有用的经验,并学到了几个有趣的教训。

我们学到的一个教训是,大型分布式系统容易受到许多类型的故障的影响,而不仅仅是许多分布式协议中假设的标准网络分区和失败停止故障。例如,我们看到了由于以下所有原因导致的问题:内存和网络损坏、大的时钟偏差、挂机、扩展和非对称网络分区、我们正在使用的其他系统中的错误(例如Chubby)、GFS配额溢出、计划内和计划外硬件维护。由于我们已经获得了更多这些问题的经验,我们通过改变各种协议来解决它们。例如,我们将校验和添加到RPC机制中。我们还通过去除系统的一部分关于另一部分的假设来处理一些问题。例如,我们停止假设给定的Chubby操作只能返回一组固定的错误。

我们学到的另一个教训是,在明确如何使用新功能之前,延迟添加新功能非常重要。例如,我们最初计划在API中支持通用事务。但是,由于我们没有立即使用它们,因此我们没有实现它们。既然我们在Bigtable上运行了许多真正的应用,我们就能够检验它们的实际需求,并发现大多数应用只需要单行事务。在人们要求分布式事务的地方,最重要的用途是维护二级索引,我们计划增加一种专门的机制来满足这种需求。新机制不如分布式事务通用,但效率更高(特别是对于跨越数百行或更多行的更新),并且还可以更好地与我们的乐观的跨数据中心复制方案进行交互。

我们从支持Bigtable中学到的实用的经验教训是适当的系统级监控的重要性(即监控Bigtable本身以及使用Bigtable的客户端进程)。例如,我们扩展了我们的RPC系统,以便对于RPC的样本,它保留了代表该RPC重要操作完成的详细跟踪。此功能使我们能够检测并修复许多问题,例如分片数据结构上的锁竞争、提交Bigtable变更时写入GFS的速度慢、以及当METADATA分片不可用时对METADATA表的访问卡顿。另一个有用的监控示例是每个Bigtable集群都在Chubby中注册。这使我们能够追踪所有集群、发现它们有多大、查看它们运行的软件版本、接收的流量、以及是否存在任何问题,例如意外的大延迟。

我们学到的最重要的教训是简单设计的价值。鉴于我们系统的大小(大约100000行非测试代码),以及代码以意想不到的方式随时间演变的事实,我们发现代码和设计的清晰度对代码维护和调试有很大帮助。其中一个例子是我们的片服务器成员协议。我们的第一个协议很简单:主服务器定期向片服务器发放租约,如果租约到期,片服务器会自行终止。遗憾的是,该协议在存在网络问题时显著降低了可用性,并且对主服务器恢复时间也很敏感。我们重新设计了协议几次,直到我们有一个表现良好的协议。但是,生成的协议过于复杂,并且依赖于其他应用很少使用的Chubby功能的行为。我们发现,我们花费了大量时间来调试模糊的角落情况,不仅在Bigtable代码中,而且在Chubby代码中。最终,我们取消了这个协议并转而采用了一种更简单的新协议,该协议完全取决于广泛使用的Chubby功能。

10. 相关工作

Boxwood项目[24]的组件在某些方面与Chubby、GFS和Bigtable重叠,因为它提供分布式协议、锁、分布式块存储和分布式B树存储。在存在重叠的每种情况下,看起来Boxwood的组件的目标水平低于相应的Google服务。Boxwood项目的目标是为构建更高级别的服务(如文件系统或数据库)提供基础设施,而Bigtable的目标是直接支持希望存储数据的客户端应用。

许多最近的项目已经解决了通过广域网(通常是“互联网规模”)提供分布式存储或更高级别服务的问题。这包括以CAN[29]、Chord[32]、Tapestry[37]和Pastry[30]等项目开始的分布式哈希表的工作。这些系统解决了Bigtable不会出现的问题,例如高度可变的带宽、不可信的参与者或频繁的重新配置; 分散控制和拜占庭容错并不是Bigtable的目标。

就应用开发者可能提供的分布式数据存储模型而言,我们认为分布式B树或分布式哈希表提供的键值对模型过于局限。键值对是一个有用的构建块,但它们不应该是为开发者提供的唯一构建块。我们选择的模型比简单的键值对更丰富,并支持稀疏的半结构化数据。尽管如此,它仍然很简单,它是一个非常有效的平面文件表示,并且它足够透明(通过位置分组),以允许我们的用户调整系统的重要行为。

一些数据库供应商开发了可以存储大量数据的并行数据库。Oracle的Real Application Cluster数据库[27]使用共享磁盘来存储数据(Bigtable使用GFS)和分布式锁管理器(Bigtable使用Chubby)。IBM的DB2 Parallel Edition[4]基于类似于Bigtable的非共享[33]架构。每个DB2服务器负责存储在本地关系数据库中表的行的子集。这两种产品对其完整的关系模型都提供了事务。

Bigtable位置分组实现了类似的压缩和磁盘读取性能优势,这些优势来自于其他在磁盘上使用基于列的存储而不是基于行的存储组织数据的系统(包括C-Store[1,34]和商业产品,如Sybase IQ[15, 36]、SenSage[31]、KDB +[22]和MonetDB/X100中的ColumnBM存储层[38])。另一个将垂直和水平数据分成平面文件并实现良好数据压缩率的系统是AT&T的Daytona数据库[19]。位置分组不支持CPU缓存级优化,例如Ailamaki[2]所描述的优化。

Bigtable使用memtables和SSTables将更新存储到分片的方式类似于Log-Structured Merge Tree[26]存储对索引数据的更新的方式。在两个系统中,排序数据在写入磁盘之前都在内存中缓存,读取必须合并内存和磁盘中的数据。

C-Store和Bigtable共享许多特性:两个系统都使用非共享体系结构,并且具有两种不同的数据结构,一种用于最近的写入,另一种用于存储长期存在的数据,具有将数据从一种形式移动到另一种形式的机制。这些系统的API差别很大:C-Store的行为类似于关系数据库,而Bigtable提供较低级别的读写接口,旨在支持每台服务器每秒数千次此类操作。C-Store也是“读取优化的关系型DBMS”,而Bigtable在读取密集型和写入密集型应用上都提供了良好的性能。

Bigtable的负载均衡器必须解决非共享数据库所面临的一些相同类型的负载和内存平衡问题(例如,[11,35])。我们的问题稍微简单一点:(1) 我们不考虑相同数据(可能是由于视图或索引的替代形式)的多个副本的可能性; (2) 我们让用户告诉我们哪些数据属于内存,哪些数据应保留在磁盘上,而不是试图动态确定; (3) 我们没有复杂的查询来执行或优化。

11. 总结

我们已经描述了Bigtable,一种在Google中用于存储结构化数据的分布式系统。Bigtable集群自2005年4月开始投入生产使用,在此之前我们在设计和实施上花费了大约7个人年。截至2006年8月,超过60个项目正在使用Bigtable。我们的用户喜欢Bigtable实现提供的性能和高可用性,并且他们可以通过在系统资源需求随时间变化时向系统添加更多计算机来扩展其集群的容量。

鉴于Bigtable的不寻常的接口,一个有趣的问题是我们的用户适应使用它有多困难。新用户有时不确定如何最好地使用Bigtable接口,特别是如果他们习惯于使用支持通用事务的关系数据库。尽管如此,许多Google产品成功使用Bigtable的事实表明我们的设计在实践中运作良好。

我们正在实现其他几个Bigtable功能,例如支持二级索引和构建跨数据中心复制的多主服务器副本的Bigtables的基础设施。我们还开始将Bigtable作为服务部署到产品团队,以便各个团队不需要维护自己的集群。随着我们服务集群的扩展,我们需要在Bigtable内部处理更多的资源共享问题[3,5]。

最后,我们发现在Google内构建自己的存储解决方案有很大的优势。通过为Bigtable设计我们自己的数据模型,我们获得了很大的灵活性。此外,我们对Bigtable的实现以及Bigtable所依赖的其他Google基础设施的控制意味着我们可以消除他们出现的瓶颈和低效率。

致谢

我们感谢匿名审稿人David Nagle和我们的上级Brad Calder对本文的反馈。Bigtable系统受益于Google内众多用户的反馈。此外,我们感谢以下人士对Bigtable的贡献:Dan Aguayo,Sameer Ajmani,Zhifeng Chen,Bill Coughran,Mike Epstein,Healfdene Goguen,Robert Griesemer,Jeremy Hylton,Josh Hyman,Alex Khesin,Joanna Kulik,Alberto Lerner, Sherry Listgarten,Mike Maloney,Eduardo Pinheiro,Kathy Polizzi,Frank Yellin和Arthur Zwiegincew。

参考文献

  1. ABADI, D. J., MADDEN, S. R., AND FERREIRA, M. C. Integrating compression and execution in columnoriented database systems. Proc. of SIGMOD (2006).
  2. AILAMAKI, A., DEWITT, D. J., HILL, M. D., AND SKOUNAKIS, M. Weaving relations for cache performance. In The VLDB Journal (2001), pp. 169-180.
  3. BANGA, G., DRUSCHEL, P., AND MOGUL, J. C. Resource containers: A new facility for resource management in server systems. In Proc. of the 3rd OSDI (Feb. 1999), pp. 45-58.
  4. BARU, C. K., FECTEAU, G., GOYAL, A., HSIAO, H., JHINGRAN, A., PADMANABHAN, S., COPELAND, G. P., AND WILSON, W. G. DB2 parallel edition. IBM Systems Journal 34, 2 (1995), 292-322.
  5. BAVIER, A., BOWMAN, M., CHUN, B., CULLER, D., KARLIN, S., PETERSON, L., ROSCOE, T., SPALINK, T., AND WAWRZONIAK, M. Operating system support for planetary-scale network services. In Proc. of the 1st NSDI (Mar. 2004), pp. 253-266.
  6. BENTLEY, J. L., AND MCILROY, M. D. Data compression using long common strings. In Data Compression Conference (1999), pp. 287-295.
  7. BLOOM, B. H. Space/time trade-offs in hash coding with allowable errors. CACM 13, 7 (1970), 422-426.
  8. BURROWS, M. The Chubby lock service for looselycoupled distributed systems. In Proc. of the 7th OSDI (Nov. 2006).
  9. CHANDRA, T., GRIESEMER, R., AND REDSTONE, J. Paxos made live —— An engineering perspective. In Proc. of PODC (2007).
  10. COMER, D. Ubiquitous B-tree. Computing Surveys 11, 2 (June 1979), 121-137.
  11. COPELAND, G. P., ALEXANDER, W., BOUGHTER, E. E., AND KELLER, T. W. Data placement in Bubba. In Proc. of SIGMOD (1988), pp. 99-108.
  12. DEAN, J., AND GHEMAWAT, S. MapReduce: Simplified data processing on large clusters. In Proc. of the 6th OSDI (Dec. 2004), pp. 137-150.
  13. DEWITT, D., KATZ, R., OLKEN, F., SHAPIRO, L., STONEBRAKER, M., AND WOOD, D. Implementation techniques for main memory database systems. In Proc. of SIGMOD (June 1984), pp. 1-8.
  14. DEWITT, D. J., AND GRAY, J. Parallel database systems: The future of high performance database systems. CACM 35, 6 (June 1992), 85-98.
  15. FRENCH, C. D. One size fits all database architectures do not work for DSS. In Proc. of SIGMOD (May 1995), pp. 449-450.
  16. GAWLICK, D., AND KINKADE, D. Varieties of concurrency control in IMS/VS fast path. Database engineering Bulletin 8, 2 (1985), 3-10.
  17. GHEMAWAT, S., GOBIOFF, H., AND LEUNG, S.-T. The Google file system. In Proc. of the 19th ACM SOSP (Dec. 2003), pp. 29-43.
  18. GRAY, J. Notes on database operating systems. In Operating Systems —— An Advanced Course, vol. 60 of Lecture Notes in Computer Science. Springer-Verlag, 1978.
  19. GREER, R. Daytona and the fourth-generation language Cymbal. In Proc. of SIGMOD (1999), pp. 525-526.
  20. HAGMANN, R. Reimplementing the Cedar file system using logging and group commit. In Proc. of the 11th SOSP (Dec. 1987), pp. 155-162.
  21. HARTMAN, J. H., AND OUSTERHOUT, J. K. The Zebra striped network file system. In Proc. of the 14th SOSP (Asheville, NC, 1993), pp. 29-43.
  22. KX.COM. kx.com/products/database.php. Product page.
  23. LAMPORT, L. The part-time parliament. ACM TOCS 16, 2 (1998), 133-169.
  24. MACCORMICK, J., MURPHY, N., NAJORK, M., THEKKATH, C. A., AND ZHOU, L. Boxwood: Abstractions as the foundation for storage infrastructure. In Proc. of the 6th OSDI (Dec. 2004), pp. 105-120.
  25. MCCARTHY, J. Recursive functions of symbolic expressions and their computation by machine. CACM 3, 4 (Apr. 1960), 184-195.
  26. O’NEIL, P., CHENG, E., GAWLICK, D., AND O’NEIL, E. The log-structured merge-tree (LSM-tree). Acta Inf. 33, 4 (1996), 351-385.
  27. ORACLE.COM. www.oracle.com/technology/products/-database/clustering/index.html. Product page.
  28. PIKE, R., DORWARD, S., GRIESEMER, R., AND QUINLAN, S. Interpreting the data: Parallel analysis with Sawzall. Scientific Programming Journal 13, 4 (2005), 227-298.
  29. RATNASAMY, S., FRANCIS, P., HANDLEY, M., KARP, R., AND SHENKER, S. A scalable content-addressable network. In Proc. of SIGCOMM (Aug. 2001), pp. 161-172.
  30. ROWSTRON, A., AND DRUSCHEL, P. Pastry: Scalable, distributed object location and routing for largescale peer-to-peer systems. In Proc. of Middleware 2001 (Nov. 2001), pp. 329-350.
  31. SENSAGE.COM. sensage.com/products-sensage.htm.Product page.
  32. STOICA, I., MORRIS, R., KARGER, D., KAASHOEK, M. F., AND BALAKRISHNAN, H. Chord: A scalable peer-to-peer lookup service for Internet applications. In Proc. of SIGCOMM (Aug. 2001), pp. 149-160.
  33. STONEBRAKER, M. The case for shared nothing. Database Engineering Bulletin 9, 1 (Mar. 1986), 4-9.
  34. STONEBRAKER,M., ABADI, D. J., BATKIN, A., CHEN, X., CHERNIACK, M., FERREIRA, M., LAU, E., LIN, A., MADDEN, S., O’NEIL, E., O’NEIL, P., RASIN, A., TRAN, N., AND ZDONIK, S. C-Store: A columnoriented DBMS. In Proc. of VLDB (Aug. 2005), pp. 553-564.
  35. STONEBRAKER, M., AOKI, P. M., DEVINE, R., LITWIN, W., AND OLSON, M. A. Mariposa: A new architecture for distributed data. In Proc. of the Tenth ICDE (1994), IEEE Computer Society, pp. 54-65.
  36. SYBASE.COM. www.sybase.com/products/databaseservers/sybaseiq. Product page.
  37. ZHAO, B. Y., KUBIATOWICZ, J., AND JOSEPH, A. D. Tapestry: An infrastructure for fault-tolerant wide-area location and routing. Tech. Rep. UCB/CSD-01-1141, CS Division, UC Berkeley, Apr. 2001.
  38. ZUKOWSKI, M., BONCZ, P. A., NES, N., AND HEMAN, S. MonetDB/X100 —— A DBMS in the CPU cache. IEEE
    Data Eng. Bull. 28, 2 (2005), 17-22.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章