本文由厦门大学计算机系教师林子雨翻译,翻译质量很高,本人只对极少数翻译得不太恰当的地方进行了修改。前端
【摘要】:Spanner 是谷歌公司研发的、可扩展的、多版本、全球分布式、同步复制数据库。它是第一个把数据分布在全球范围内的系统,而且支持外部一致性的分布式事务。本文描述了 Spanner 的架构、特性、不一样设计决策的背后机理和一个新的时间 API,这个 API 能够暴露时钟的不肯定性。这个 API 及其实现,对于支持外部一致性和许多强大特性而言,是很是重要的,这些强大特性包括:非阻塞的读、不采用锁机制的只读事务、原子模式变动。算法
【关键词】Google Spanner, Bigtable, distributed database数据库
Spanner 是一个可扩展的、全球分布式的数据库,是在谷歌公司设计、开发和部署的。编程
在最高抽象层面,Spanner 就是一个数据库,把数据分片存储在许多 Paxos[21]状态机上,这些机器位于遍及全球的数据中心内。复制技术能够用来服务于全球可用性和地理局部性。客户端会自动在副本之间进行失败恢复。随着数据的变化和服务器的变化,Spanner 会自动把数据进行从新分片,从而有效应对负载变化和处理失败。Spanner 被设计成能够扩展到几百万个机器节点,跨越成百上千个数据中心,具有几万亿数据库行的规模。缓存
应用能够借助于 Spanner 来实现高可用性,经过在一个洲的内部和跨越不一样的洲之间复制数据,保证即便面对大范围的天然灾害时数据依然可用。咱们最初的客户是 F1[35],一个谷歌广告后台的从新编程实现。F1 使用了跨越美国的 5 个副本。绝大多数其余应用极可能会在属于同一个地理范围内的 3-5 个数据中心内放置数据副本,采用相对独立的失败模式。也就是说,许多应用都会首先选择低延迟,而不是高可用性,只要系统可以从 1-2 个数据中心失败中恢复过来。安全
Spanner 的主要工做,就是管理跨越多个数据中心的数据副本,可是,在咱们的分布式系统体系架构之上设计和实现重要的数据库特性方面,咱们也花费了大量的时间。尽管有许多项目能够很好地使用 BigTable[9],咱们也不断收到来自客户的抱怨,客户反映 BigTable 没法应用到一些特定类型的应用上面,好比具有复杂可变的模式,或者对于在大范围内分布的多个副本数据具备较高的一致性要求。其余研究人员也提出了相似的抱怨[37]。谷歌的许多应用已经选择使用 Megastore[5],主要是由于它的半关系数据模型和对同步复制的支持,尽管 Megastore 具有较差的写操做吞吐量。因为上述多个方面的因素,Spanner 已经从一个相似 BigTable 的单一版本的键值存储,演化成为一个具备时间属性的多版本的数据库。数据被存储到模式化的、半关系的表中,数据被版本化,每一个版本都会自动以提交时间做为时间戳,旧版本的数据会更容易被垃圾回收。应用能够读取旧版本的数据。Spanner 支持通用的事务,提供了基于 SQL 的查询语言。服务器
做为一个全球分布式数据库,Spanner 提供了几个有趣的特性:第一,在数据的副本配置方面,应用能够在一个很细的粒度上进行动态控制。应用能够详细规定,哪些数据中心包含哪些数据,数据距离用户有多远(控制用户读取数据的延迟),不一样数据副本之间距离有多远(控制写操做的延迟),以及须要维护多少个副本(控制可用性和读操做性能)。数据也能够被动态和透明地在数据中心之间进行移动,从而平衡不一样数据中心内资源的使用。第二, Spanner 有两个重要的特性,很难在一个分布式数据库上实现,即 Spanner 提供了读和写操做的外部一致性,以及在一个时间戳下面的跨越数据库的全球一致性的读操做。这些特性使得 Spanner 能够支持一致的备份、一致的 MapReduce 执行[12]和原子模式变动,全部都是在全球范围内实现,即便存在正在处理中的事务也能够。网络
之因此能够支持这些特性,是由于 Spanner 能够为事务分配全球范围内有意义的提交时间戳,即便事务多是分布式的。这些时间戳反映了事务序列化的顺序。除此之外,这些序列化的顺序知足了外部一致性的要求:若是一个事务 T1 在另外一个事务 T2 开始以前就已经提交了,那么,T1 的时间戳就要比 T2 的时间戳小。Spanner 是第一个能够在全球范围内提供这种保证的系统。数据结构
实现这种特性的关键技术就是一个新的 TrueTime API 及其实现。这个 API 能够直接暴露时钟不肯定性,Spanner 时间戳的保证就是取决于这个 API 实现的界限。若是这个不肯定性很大,Spanner 就下降速度来等待这个大的不肯定性结束。谷歌的簇管理器软件提供了一个 TrueTime API 的实现。这种实现能够保持较小的不肯定性(一般小于 10ms),主要是借助于现代时钟参考值(好比 GPS 和原子钟)。架构
第 2 部分描述了 Spanner 实现的结构、特性集和工程方面的决策;第 3 部分介绍咱们的新的 TrueTime API,而且描述了它的实现;第 4 部分描述了 Spanner 如何使用 TrueTime 来实现外部一致性的分布式事务、不用锁机制的只读事务和原子模式更新。第 5 部分提供了测试 Spanner 性能和 TrueTime 行为的测试基准,并讨论了 F1 的经验。第 六、7 和 8 部分讨论了相关工做,并给出总结。
本部份内容描述了 Spanner 的结构和背后的实现机理,而后描述了目录抽象,它被用来管理副本和局部性,并介绍了数据的转移单位。最后,将讨论咱们的数据模型,从而说明为何 Spanner 看起来更加像一个关系数据库,而不是一个键值数据库;还会讨论应用如何能够控制数据的局部性。
一个 Spanner 部署称为一个 universe。假设 Spanner 在全球范围内管理数据,那么,将会只有可数的、运行中的 universe。咱们当前正在运行一个测试用的 universe,一个部署/线上用的 universe 和一个只用于线上应用的 universe。
Spanner 被组织成许多个 zone 的集合,每一个 zone 都大概像一个 BigTable 服务器的部署。 zone 是管理部署的基本单元。zone 的集合也是数据能够被复制到的位置的集合。当新的数据中心加入服务,或者老的数据中心被关闭时,zone 能够被加入到一个运行的系统中,或者从中移除。zone 也是物理隔离的单元,在一个数据中心中,可能有一个或者多个 zone, 例如,当属于不一样应用的数据必须被分区存储到同一个数据中心的不一样服务器集合中时,一个数据中心就会有多个 zone 。
图 1 显示了在一个 Spanner 的 universe 中的服务器。一个 zone 包括一个 zonemaster, 和一百至几千个 spanserver。Zonemaster 把数据分配给 spanserver,spanserver 把数据提供给客户端。客户端使用每一个 zone 上面的 location proxy 来定位能够为本身提供数据的 spanserver。Universe master 和 placement driver,当前都只有一个。Universe master 主要是一个控制台,它显示了关于 zone 的各类状态信息,能够用于相互之间的调试。Placement driver 会周期性地与 spanserver 进行交互,来发现那些须要被转移的数据,或者是为了知足新的副本约束条件,或者是为了进行负载均衡。
本部份内容主要关注 spanserver 实现,来解释复制和分布式事务是如何被架构到咱们的基于 BigTable 的实现之上的。图 2 显示了软件栈。在底部,每一个 spanserver 负载管理 100-1000 个称为 tablet 的数据结构的实例。一个 tablet 就相似于 BigTable 中的 tablet,也实现了下面的映射: (key:string, timestamp:int64)->string
与 BigTable 不一样的是,Spanner 会把时间戳分配给数据,这种很是重要的方式,使得 Spanner 更像一个多版本数据库,而不是一个键值存储。一个 tablet 的状态是存储在相似于 B-树的文件集合和写前(write-ahead)的日志中,全部这些都会被保存到一个分布式的文件系统中,这个分布式文件系统被称为 Colossus,它继承自 Google File System。
为了支持复制,每一个 spanserver 会在每一个 tablet 上面实现一个单个的 Paxos 状态机。一个以前实现的Spanner 能够支持在每一个 tablet 上面实现多个 Paxos 状态机器,它能够容许更加灵活的复制配置,可是,这种设计过于复杂,被咱们舍弃了。每一个状态机器都会在相应的 tablet 中保存本身的元数据和日志。咱们的 Paxos 实现支持长寿命的领导者(采用基于时间的领导者租约),时间一般在 0 到 10 秒之间。当前的 Spanner 实现中,会对每一个 Paxos 写操做进行两次记录:一次是写入到 tablet 日志中,一次是写入到 Paxos 日志中。这种作法只是权宜之计,咱们之后会进行完善。咱们在 Paxos 实现上采用了管道化的方式,从而能够在存在广域网延迟时改进 Spanner 的吞吐量,可是,Paxos 会把写操做按照顺序的方式执行。
Paxos 状态机是用来实现一系列被一致性复制的映射。每一个副本的键值映射状态,都会被保存到相应的 tablet 中。写操做必须在领导者上初始化 Paxos 协议,读操做能够直接从底层的任何副本的 tablet 中访问状态信息,只要这个副本足够新。副本的集合被称为一个 Paxos group。
对于每一个是领导者的副本而言,每一个 spanserver 会实现一个锁表来实现并发控制。这个锁表包含了两阶段锁机制的状态:它把键的值域映射到锁状态上面。注意,采用一个长寿命的 Paxos 领导者,对于有效管理锁表而言是很是关键的。在 BigTable 和 Spanner 中,咱们都专门为长事务作了设计,好比,对于报表操做,可能要持续几分钟,当存在冲突时,采用乐观并发控制机制会表现出不好的性能。对于那些须要同步的操做,好比事务型的读操做,须要得到锁表中的锁,而其余类型的操做则能够不理会锁表。
对于每一个扮演领导者角色的副本,每一个 spanserver 也会实施一个事务管理器来支持分布式事务。这个事务管理器被用来实现一个 participant leader,该组内的其余副本则是做为 participant slaves。若是一个事务只包含一个 Paxos 组(对于许多事务而言都是如此),它就能够绕过事务管理器,由于锁表和 Paxos 两者一块儿能够保证事务性。若是一个事务包含了多 于一个 Paxos 组,那些组的领导者之间会彼此协调合做完成两阶段提交。其中一个参与者组,会被选为协调者,该组的 participant leader 被称为 coordinator leader,该组的 participant slaves 被称为 coordinator slaves。每一个事务管理器的状态,会被保存到底层的 Paxos 组。
在一系列键值映射的上层,Spanner 实现支持一个被称为“目录”的桶抽象,也就是包含公共前缀的连续键的集合。(选择“目录”做为名称,主要是因为历史沿袭的考虑,实际 上更好的名称应该是“桶”)。咱们会在第 2.3 节解释前缀的源头。对目录的支持,可让应用经过选择合适的键来控制数据的局部性。
一个目录是数据放置的基本单元。属于一个目录的全部数据,都具备相同的副本配置。 当数据在不一样的 Paxos 组之间进行移动时,会一个目录一个目录地转移,如图 3 所示。Spanner 可能会移动一个目录从而减轻一个 Paxos 组的负担,也可能会把那些被频繁地一块儿访问的目录都放置到同一个组中,或者会把一个目录转移到距离访问者更近的地方。当客户端操做正在进行时,也能够进行目录的转移。咱们能够预期在几秒内转移 50MB 的目录。
一个 Paxos 组能够包含多个目录,这意味着一个 Spanner tablet 是不一样于一个 BigTable tablet 的。一个 Spanner tablet 没有必要是一个行空间内按照词典顺序连续的分区,相反,它能够是行空间内的多个分区。咱们作出这个决定,是由于这样作可让多个被频繁一块儿访问的目录被整合到一块儿。
Movedir 是一个后台任务,用来在不一样的 Paxos 组之间转移目录[14]。Movedir 也用来为 Paxos 组增长和删除副本[25],由于 Spanner 目前还不支持在一个 Paxos 内部进行配置的变动。 Movedir 并非做为一个事务来实现,这样能够避免在一个块数据转移过程当中阻塞正在进行的读操做和写操做。相反,Movedir 会注册一个事实(fact),代表它要转移数据,而后在后台运行转移数据。当它几乎快要转移完指定数量的数据时,就会启动一个事务来自动转移那部分数据,而且为两个 Paxos 组更新元数据。
一个目录也是一个应用能够指定的地理复制属性(即放置策略)的最小单元。咱们的放置规范语言的设计,把管理复制的配置这个任务单独分离出来。管理员须要控制两个维度: 副本的数量和类型,以及这些副本的地理放置属性。他们在这两个维度里面建立了一个命名 选项的菜单。经过为每一个数据库或单独的目录增长这些命名选项的组合,一个应用就能够控制数据的复制。例如,一个应用可能会在本身的目录里存储每一个终端用户的数据,这就有可能使得用户 A 的数据在欧洲有三个副本,用户 B 的数据在北美有 5 个副本。
为了表达的清晰性,咱们已经作了尽可能简化。事实上,当一个目录变得太大时,Spanner 会把它分片存储。每一个分片可能会被保存到不一样的 Paxos 组上(所以就意味着来自不一样的服 务器)。Movedir 在不一样组之间转移的是分片,而不是转移整个目录。
Spanner 会把下面的数据特性集合暴露给应用:基于模式化的半关系表的数据模型,查询语言和通用事务。支持这些特性的动机,是受到许多因素驱动的。须要支持模式化的半关系表是由 Megastore[5]的普及来支持的。在谷歌内部至少有 300 个应用使用 Megastore(尽 管它具备相对低的性能),由于它的数据模型要比 BigTable 简单,更易于管理,而且支持在跨数据中心层面进行同步复制。BigTable 只能够支持跨数据中心的最终事务一致性。使用 Megastore 的著名的谷歌应用是 Gmail,Picasa,Calendar,Android Market, AppEngine。在 Spanner 中须要支持 SQL 类型的查询语言,也很显然是很是必要的,由于 Dremel[28]做为交互式分析工具已经很是普及。最后,在 BigTable 中跨行事务的缺少来致使了用户频繁的抱怨; Percolator[32]的开发就是用来部分解决这个问题的。一些做者都在抱怨,通用的两阶段提交的代价过于昂贵,由于它会带来可用性问题和性能问题[9][10][19]。咱们认为,最好让应用 程序开发人员来处理因为过分使用事务引发的性能问题,而不是老是围绕着“缺乏事务”进 行编程。在 Paxos 上运行两阶段提交弱化了可用性问题。
应用的数据模型是架构在被目录桶装的键值映射层之上。一个应用会在一个 universe 中建立一个或者多个数据库。每一个数据库能够包含无限数量的模式化的表。每一个表都和关系数据库表相似,具有行、列和版本值。咱们不会详细介绍 Spanner 的查询语言,它看起来很像 SQL,只是作了一些扩展。
Spanner 的数据模型不是纯粹关系型的,它的行必须有名称。更准确地说,每一个表都需 要有包含一个或多个主键列的排序集合。这种需求,让 Spanner 看起来仍然有点像键值存储: 主键造成了一个行的名称,每一个表都定义了从主键列到非主键列的映射。当一个行存在时,必需要求已经给行的一些键定义了一些值(即便是 NULL)。采用这种结构是颇有用的,由于这可让应用经过选择键来控制数据的局部性。
图 4 包含了一个 Spanner 模式的实例,它是以每一个用户和每一个相册为基础存储图片元数据。这个模式语言和 Megastore 的相似,同时增长了额外的要求,即每一个 Spanner 数据库必 须被客户端分割成一个或多个表的层次结构(hierarchy)。客户端应用会使用 INTERLEAVE IN 语句在数据库模式中声明这个层次结构。这个层次结构上面的表,是一个目录表。目录表中的每行都具备键 K,和子孙表中的全部以 K 开始(以字典顺序排序)的行一块儿,构成了一个目录。ON DELETE CASCADE 意味着,若是删除目录中的一个行,也会级联删除全部相关的子孙行。这个图也解释了这个实例数据库的交织层次(interleaved layout),例如 Albums(2,1) 表明了来自 Albums 表的、对应于 user_id=2 和 album_id=1 的行。这种表的交织层次造成目录,是很是重要的,由于它容许客户端来描述存在于多个表之间的位置关系,这对于一个分片的分布式数据库的性能而言是很重要的。没有它的话,Spanner 就没法知道最重要的位置关系。
本部份内容描述 TrueTime API,并大概给出它的实现方法。咱们把大量细节内容放在另外一篇论文中,咱们的目标是展现这种 API 的力量。表 1 列出了 API 的方法。TrueTime 会显式地把时间表达成 TTinterval,这是一个时间区间,具备有界限的时间不肯定性(不像其余 的标准时间接口,没有为客户端提供―不肯定性‖这种概念)。TTinterval 区间的端点是 TTstamp 类型。TT.now()方法会返回一个 TTinterval,它能够保证包含 TT.now()方法在调用时的绝对 时间。这个时间和具有闰秒涂抹(leap-second smearing)的 UNIX 时间同样。把即时偏差边 界定义为 ε,平均偏差边界为ε。TT.after()和 TT.before()方法是针对 TT.now()的便捷的包装器。
表示一个事件 e 的绝对时间,能够利用函数 tabs(e)。若是用更加形式化的术语,TrueTime 能够保证,对于一个调用 tt=TT.now(),有 tt.earliest≤tabs(enow)≤tt.latest,其中, enow 是调用的事件。
在底层,TrueTime 使用的时间是 GPS 和原子钟。TrueTime 使用两种类型的时间,是由于它们有不一样的失败模式。GPS 参考时间的弱点是天线和接收器失效、局部电磁干扰和相关失败(好比设计上的缺陷致使没法正确处理闰秒和电子欺骗),以及 GPS 系统运行中断。原子钟也会失效,不过失效的方式和 GPS 无关,不一样原子钟之间的失效也没有彼此关联。 因为存在频率偏差,在通过很长的时间之后,原子钟都会产生明显偏差。
TrueTime 是由每一个数据中心上面的许多 time master 机器和每台机器上的一个 timeslave daemon 来共同实现的。大多数 master 都有具有专用天线的 GPS 接收器,这些 master 在物理上是相互隔离的,这样能够减小天线失效、电磁干扰和电子欺骗的影响。剩余的 master (咱们称为 Armageddon master)则配备了原子钟。一个原子钟并非很昂贵:一个 Armageddon master 的花费和一个 GPS master 的花费是同一个数量级的。全部 master 的时间 参考值都会进行彼此校对。每一个 master 也会交叉检查时间参考值和本地时间的比值,若是两者差异太大,就会把本身驱逐出去。在同步期间,Armageddon master 会表现出一个逐渐增长的时间不肯定性,这是由保守应用的最差时钟漂移引发的。GPS master 表现出的时间不肯定性几乎接近于 0。
每一个 daemon 会从许多 master[29]中收集投票,得到时间参考值,从而减小偏差。被选中的 master 中,有些 master 是 GPS master,是从附近的数据中心得到的,剩余的 GPS master 是从远处的数据中心得到的;还有一些是 Armageddon master。Daemon 会使用一个 Marzullo 算法[27]的变种,来探测和拒绝欺骗,而且把本地时钟同步到非撒谎 master 的时间参考值。 为了免受较差的本地时钟的影响,咱们会根据组件规范和运行环境肯定一个界限,若是机器的本地时钟偏差频繁超出这个界限,这个机器就会被驱逐出去。
在同步期间,一个 daemon 会表现出逐渐增长的时间不肯定性。ε 是从保守应用的最差 时钟漂移中获得的。ε 也取决于 time master 的不肯定性,以及与 time master 之间的通信延迟。在咱们的线上应用环境中,ε 一般是一个关于时间的锯齿形函数。在每一个投票间隔中, ε 会在 1 到 7ms 之间变化。所以,在大多数状况下,ε的值是 4ms。Daemon 的投票间隔,在当前是 30 秒,当前使用的时钟漂移比率是 200 微秒/秒,两者一块儿意味着 0 到 6ms 的锯齿形边界。剩余的 1ms 主要来自到 time master 的通信延迟。在失败的时候,超过这个锯齿形边界也是有可能的。例如,偶尔的 time master 不肯定性,可能会引发整个数据中心范围内的 ε 值的增长。相似的,过载的机器或者网络链接,都会致使 ε 值偶尔地局部增大。
本部份内容描述 TrueTime 如何能够用来保证并发控制的正确性,以及这些属性如何用来实现一些关键特性,好比外部一致性的事务、无锁机制的只读事务、针对历史数据的非阻塞读。这些特性能够保证,在时间戳为 t 的时刻的数据库读操做,必定只能看到在 t 时刻之 前已经提交的事务。
进一步说,把 Spanner 客户端的写操做和 Paxos 看到的写操做这两者进行区分,是很是重要的,咱们把 Paxos 看到的写操做称为 Paxos 写操做。例如,两阶段提交会为准备提交阶段生成一个 Paxos 写操做,这时不会有相应的客户端写操做。
表 2 列出了 Spanner 支持的操做的类型。Spanner 能够支持读写事务、只读事务(预先声明的快照隔离事务)和快照读。独立写操做,会被当成读写事务来执行。非快照独立读操做,会被当成只读事务来执行。两者都是在内部进行 retry,客户端不用进行这种 retry loop。
一个只读事务具有快照隔离的性能优点[6]。一个只读事务必须事先被声明不会包含任何写操做,它并非一个简单的不包含写操做的读写事务。在一个只读事务中的读操做,在执行时会采用一个系统选择的时间戳,不包含锁机制,所以,后面到达的写操做不会被阻塞。 在一个只读事务中的读操做,能够到任何足够新的副本上去执行(见第 4.1.3 节)。
一个快照读操做,是针对历史数据的读取,执行过程当中,不须要锁机制。一个客户端能够为快照读肯定一个时间戳,或者提供一个时间范围让 Spanner 来自动选择时间戳。无论是 哪一种状况,快照读操做均可以在任何具备足够新的副本上执行。
对于只读事务和快照读而言,一旦已经选定一个时间戳,那么,提交就是不可避免的,除非在那个时间点的数据已经被垃圾回收了。所以,客户端没必要在 retry loop 中缓存结果。 当一个服务器失效的时候,客户端就可使用一样的时间戳和当前的读位置,在另一个服务器上继续执行读操做。
Spanner 的 Paxos 实现中使用了时间化的租约,来实现长时间的领导者地位(默认是 10秒)。一个潜在的领导者会发起请求,请求时间化的租约投票,在收到指定数量的投票后,这个领导者就能够肯定本身拥有了一个租约。一个副本在成功完成一个写操做后,会隐式地延期本身的租约。对于一个领导者而言,若是它的租约快要到期了,就要显示地请求租约延期。另外一个领导者的租约有个时间区间,这个时间区间的起点就是这个领导者得到指定数量的投票那一刻,时间区间的终点就是这个领导者失去指定数量的投票的那一刻(由于有些投 票已通过期了)。Spanner 依赖于下面这些“不连贯性”:对于每一个 Paxos 组,每一个 Paxos 领 导者的租约时间区间,是和其余领导者的时间区间彻底隔离的。附录 A 显示了如何强制实现这些不连贯性。
Spanner 实现容许一个 Paxos 领导者经过把 slave 从租约投票中释放出来这种方式,实现领导者的退位。为了保持这种彼此隔离的不连贯性,Spanner 会对何时退位作出限制。把 smax 定义为一个领导者可使用的最大的时间戳。在退位以前,一个领导者必须等到 TT.after(smax)是真。
事务读和写采用两段锁协议。当全部的锁都已经得到之后,在任何锁被释放以前,就能够给事务分配时间戳。对于一个给定的事务,Spanner 会为事务分配时间戳,这个时间戳是 Paxos 分配给 Paxos 写操做的,它表明了事务提交的时间。
Spanner 依赖下面这些单调性:在每一个 Paxos 组内,Spanner 会以单调增长的顺序给每一个 Paxos 写操做分配时间戳,即便在跨越多个领导者时也是如此。一个单个的领导者副本,能够很容易地以单调增长的方式分配时间戳。在多个领导者之间就会强制实现彼此隔离的不连 贯:一个领导者必须只能分配属于它本身租约时间区间内的时间戳。要注意到,一旦一个时间戳 s 被分配,smax 就会被增长到 s,从而保证彼此隔离性(不连贯性)。
Spanner 也会实现下面的外部一致性:若是一个事务 T2 在事务 T1 提交之后开始执行, 那么,事务 T2 的时间戳必定比事务 T1 的时间戳大。对于一个事务 Ti 而言,定义开始和提交事件eistart和eicommit,事务提交时间为si。对外部一致性的要求就变成了:
tabs(e1commit )<tabs(e2start ) s1<s2。执行事务的协议和分配时间戳的协议,遵照两条规则,两者一块儿保证外部一致性。对于一个写操做 Ti 而言,担任协调者的领导者发出的提交请求的事件为eiserver 。
Start. 为一个事务 Ti 担任协调者的领导者分配一个提交时间戳 si,不会小于 TT.now().latest 的值,TT.now().latest的值是在esierver事件以后计算获得的。要注意,担任参与者的领导者, 在这里不起做用。第 4.2.1 节描述了这些担任参与者的领导者是如何参与下一条规则的实现的。
Commit Wait. 担任协调者的领导者,必须确保客户端不能看到任何被 Ti 提交的数据,直到 TT.after(si)为真。提交等待,就是要确保 si 会比 Ti 的绝对提交时间小。提交等待的实如今 4.2.1 节中描述。证实以下:
第 4.1.2 节中描述的单调性,使得 Spanner 能够正确地肯定一个副本是否足够新,从而可以知足一个读操做的要求。每一个副本都会跟踪记录一个值,这个值被称为安全时间 tsafe,它是一个副本最近更新后的最大时间戳。若是一个读操做的时间戳是 t,当知足 t<=tsafe 时, 这个副本就能够被这个读操做读取。
。。。
一个只读事务分红两个阶段执行:分配一个时间戳 sread[8],而后当成 sread 时刻的快照读来执行事务读操做。快照读能够在任何足够新的副本上面执行。
在一个事务开始后的任意时刻,能够简单地分配 sread=TT.now().latest,经过第 4.1.2 节中描述过的相似的方式来维护外部一致性。可是,对于时间戳 sread 而言,若是 tsafe 没有增长到足够大,可能须要对 sread 时刻的读操做进行阻塞。除此之外还要注意,选择一个 sread 的值可 能也会增长 smax 的值,从而保证不连贯性。为了减小阻塞的几率,Spanner 应该分配能够保持外部一致性的最老的时间戳。第 4.2.2 节描述了如何选择这种时间戳。
这部份内容介绍一些读写操做和只读操做的实践细节,以及用来实现原子模式变动的特定事务的实现方法。而后,描述一些基本模式的细化。
就像 Bigtable 同样,发生在一个事务中的写操做会在客户端进行缓存,直到提交。由此致使的结果是,在一个事务中的读操做,不会看到这个事务的写操做的结果。这种设计在 Spanner 中能够很好地工做,由于一个读操做能够返回任何数据读的时间戳,未提交的写操做尚未被分配时间戳。
在读写事务内部的读操做,使用伤停等待(wound-wait)[33]来避免死锁。客户端对位于合适组内的领导者副本发起读操做,须要首先得到读锁,而后读取最新的数据。当一个客户端事务保持活跃的时候,它会发送“保持活跃”信息,防止那些参与的领导者让该事务过期。当一个客户端已经完成了全部的读操做,而且缓冲了全部的写操做,它就开始两阶段提交。客户端选择一个协调者组,而且发送一个提交信息给每一个参与的、具备协调者标识的领导者,并发送提交信息给任何缓冲的写操做。让客户端发起两阶段提交操做,能够避免在大范围链接内发送两次数据。
一个参与其中的、扮演非协调者角色的领导者,首先须要得到写锁。而后,它会选择一 个预备时间戳,这个时间戳应该比以前分配给其余事务的任什么时候间戳都要大(这样能够保持 单调性),而且经过 Paxos 把准备提交记录写入日志。而后,每一个参与者就把本身的准备时 间戳通知给协调者。
扮演协调者的领导者,也会首先得到写锁,可是,会跳过准备阶段。在从全部其余的、扮演参与者的领导者那里得到信息后,它就会为整个事务选择一个时间戳。这个提交时间戳 s 必须大于或等于全部的准备时间戳(这是为了知足第 4.1.3 节讨论的限制条件),在协调者收到它的提交信息时,s 应该大于 TT.now().latest,而且 s 应该大于这个领导者为以前的其余 全部事务分配的时间戳(再次指出,这样作是为了知足单调性)。这个扮演协调者的领导者,就会经过 Paxos 在日志中写入一个提交记录(或者当等待其余参与者发生超时就在日志中写 入终止记录)。
在容许任何协调者副本去提交记录以前,扮演协调者的领导者会一直等待到 TT.after(s), 从而能够保证遵循第 4.1.2 节中描述的提交等待规则。由于,扮演协调者的领导者会根据 TT.now().latest 来选择 s,并且必须等待直到那个时间戳能够确保成为过去,预期的等待时间 至少是 2*ε。这种等待时间一般会和 Paxos 通讯时间发生重叠。在提交等待以后,协调者就会发送一个提交时间戳给客户端和全部其余参与的领导者。每一个参与的领导者会经过 Paxos 把事务结果写入日志。全部的参与者会在同一个时间戳进行提交,而后释放锁。
分配一个时间戳须要一个协商阶段,这个协商发生在全部参与到该读操做中的 Paxos 组之间。由此致使的结果是,Spanner 须要为每一个只读事务提供一个 scope 表达式,它能够指出整个事务须要读取哪些键。对于单独的查询,Spanner 能够自动计算出 scope。
若是 scope 的值是由单个 Paxos 组来提供的,那么,客户端就会给那个组的领导者发起一个只读事务(当前的 Spanner 实现中,只会为 Paxos leader 中的只读事务选择一个时间戳), 为那个领导者分配 sread 而且执行读操做。对于一个单个位置的读操做,Spanner 一般会比 TT.now().latest 作得更好。咱们把 LastTS()定义为在 Paxos 组中最后提交的写操做的时间戳。若是没有准备提交的事务,这个分配到的时间戳 sread=LastTS()就很容易知足外部一致性要求: 这个事务将能够看见最后一个写操做的结果,而后排队排在它以后。
若是 scope 的值是由多个 Paxos 组来提供的,就会有几种选择。最复杂的选择就是,和全部组的领导者进行一轮沟通,你们根据 LastTS()进行协商获得 sread。Spanner 当前实现了一个更加简单的选择。这个选择能够避免一轮协商,让读操做在 sread=TT.now().latest 时刻去 执行(这可能会等待安全时间的增长)。这个事务中的全部读操做,能够被发送到任何足够 新的副本上执行。
TrueTime 容许 Spanner 支持原子模式变动。使用一个标准的事务是不可行的,由于参与者的数量(即数据库中组的数量)可能达到几百万个。Bigtable 能够支持在一个数据中心内进行原子模式变动,可是,这个操做会阻塞全部其余操做。
一个 Spanner 模式变动事务一般是一个标准事务的、非阻塞的变种。首先,它会显式地分配一个将来的时间戳,这个时间戳会在准备阶段进行注册。由此,跨越几千个服务器的模式变动,能够在不打扰其余并发活动的前提下完成。其次,读操做和写操做,它们都是隐式地依赖于模式,它们都会和任何注册的模式变动时间戳t保持同步:当它们的时间戳小于 t 时, 读写操做就执行到时刻 t;当它们的时间戳大于时刻 t 时,读写操做就必须阻塞,在模式变动事务后面进行等待。若是没有 TrueTime,那么定义模式变动发生在 t 时刻,就变得毫无心义。
咱们对 Spanner 性能进行了测试,包括复制、事务和可用性。而后,咱们提供了一些关于 TrueTime 的实验数据,而且提供了咱们的第一个用例——F1。
表 3 给出了一用于 Spanner 的微测试基准(microbenchmark)。这些测试是在分时机器上实现的:每一个 spanserver 采用 4GB 内存和四核 CPU(AMD Barcelona 2200MHz)。客户端运行在单独的机器上。每一个 zone 都包含一个 spanserver。客户端和 zone 都放在一个数据中心集合内,它们之间的网络距离不会超过 1ms。这种布局是很普通的,许多数据并不须要把数 据分散存储到全球各地)。测试数据库具备 50 个 Paxos 组和 2500 个目录。操做都是独立的 4KB 大小的读和写。All reads were served out of memory after a compaction,从而使得咱们只须要衡量 Spanner 调用栈的开销。此外,还会进行一轮读操做,来预热任何位置的缓存。
对于延迟实验而言,客户端会发起足够少许的操做,从而避免在服务器中发生排队。从 1 个副本的实验中,提交等待大约是 5ms,Paxos 延迟大约是 9ms。随着副本数量的增长, 延迟大约保持不变,只具备不多的标准差,由于在一个组的副本内,Paxos 会并行执行。随着副本数量的增长,得到指定投票数量的延迟对一个 slave 副本的慢速度不会很敏感。
对于吞吐量的实验而言,客户端发起足够数量的操做,从而使得 CPU 处理能力达到饱和。快照读操做能够在任何足够新的副本上进行,所以,快照读的吞吐量会随着副本的数量增长而线性增长。单个读的只读事务,只会在领导者上执行,由于,时间戳分配必须发生在领导者上。只读事务吞吐量会随着副本数量的增长而增长,由于有效的 spanserver 的数量会增长:在这个实验的设置中,spanserver 的数量和副本的数量相同,领导者会被随机分配到不一样的 zone。写操做的吞吐量也会从这种实验设置中得到收益(副本从 3 变到 5 时写操做吞吐量增长了,就可以说明这点),可是,随着副本数量的增长,每一个写操做执行时须要完 成的工做量也会线性增长,这就会抵消前面的收益。
表 4 显示了两阶段提交能够扩展到合理数量的参与者:它是对一系列实验的总结,这些实验运行在 3 个 zone 上,每一个 zone 具备 25 个 spanserver。扩展到 50 个参与者,不管在平均值仍是第 99 个百分位方面,都是合理的。在 100 个参与者的情形下,延迟开发明显增长。
图 5 显示了在多个数据中心运行 Spanner 时的可用性方面的收益。它显示了三个吞吐量实验的结果,而且存在数据中心失败的情形,全部三个实验结果都被重叠放置到一个时间轴 上。测试用的 universe 包含 5 个 zone Zi,每一个 zone 都拥有 25 个 spanserver。测试数据库被 分片成 1250 个 Paxos 组,100 个客户端不断地发送非快照读操做,累积速率是每秒 50K 个读操做。全部领导者都会被显式地放置到 Z1。每一个测试进行 5 秒钟之后,一个 zone 中的全部服务器都会被“杀死”:non-leader 杀掉 Z2,leader-hard 杀掉 Z1,leader-soft 杀掉 Z1,可是,它会首先通知全部服务器它们将要交出领导权。
杀掉 Z2 对于读操做吞吐量没有影响。杀掉 Z1,给领导者一些时间来把领导权交给另外一个 zone 时,会产生一个小的影响:吞吐量会降低,不是很明显,大概降低 3-4%。另外一方面,没有预警就杀掉 Z1 有一个明显的影响:完成率几乎降低到 0。随着领导者被从新选择,系统的吞吐量会增长到大约每秒 100K 个读操做,主要是因为咱们的实验设置:系统中有额外的能力,当找不到领导者时操做会排队。由此致使的结果是,系统的吞吐量会增长直到到达 系统恒定的速率。
咱们能够看看把 Paxos 领导者租约设置为 10ms 的效果。当咱们杀掉这个 zone,对于这 个组的领导者租约的过时时间,会均匀地分布到接下来的 10 秒钟内。来自一个死亡的领导者的每一个租约一旦过时,就会选择一个新的领导者。大约在杀死时间过去 10 秒钟之后,全部的组都会有领导者,吞吐量就恢复了。短的租约时间会下降服务器死亡对于可用性的影响, 可是,须要更多的更新租约的网络通信开销。咱们正在设计和实现一种机制,它能够在领导者失效的时候,让 slave 释放 Paxos 领导者租约。
关于 TrueTime,必须回答两个问题: ε 是否就是时钟不肯定性的边界? ε 会变得多糟糕? 对于第一个问题,最严峻的问题就是,若是一个局部的时钟漂移大于 200us/sec,那就会破坏 TrueTime 的假设。咱们的机器统计数据显示,坏的 CPU 的出现几率要比坏的时钟出现几率大 6 倍。也就是说,与更加严峻的硬件问题相比,时钟问题是不多见的。由此,咱们也相信,TrueTime 的实现和 Spanner 其余软件组件同样,具备很好的可靠性,值得信任。
图 6 显示了 TrueTime 数据,是从几千个 spanserver 中收集的,这些 spanserver 跨越了多 个数据中心,距离 2200 千米以上。图中描述了 ε 的第 90 个、99 个和 99.9 个百分位的状况, 是在对 timemaster 进行投票后当即对 timeslave daemon 进行样本抽样的。这些抽样数据没有考虑因为时钟不肯定性带来的 ε 值的锯齿,所以测量的是 timemaster 不肯定性(一般是 0) 再加上通信延迟。
图 6 中的数据显示了,在决定 ε 的基本值方面的上述两个问题,一般都不会是个问题。 可是,可能会存在明显的拖尾延迟问题,那会引发更高的 ε 值。图中,3 月 30 日拖尾延迟的下降,是由于网络的改进,减小了瞬间网络链接的拥堵。在 4 月 13 日 ε 的值增长了,持续了大约 1 个小时,主要是由于例行维护时关闭了两个 time master。咱们会继续调研而且消除引发 TrueTime 突变的因素。
Spanner 在 2011 年早期开始进行在线负载测试,它是做为谷歌广告后台 F1[35]的从新实现的一部分。这个后台最开始是基于 MySQL 数据库,在许多方面都采用手工数据分区。未 经压缩的数据能够达到几十 TB,虽然这对于许多 NoSQL 实例而言数据量是很小的,可是, 对于采用数据分区的 MySQL 而言,数据量是很是大的。MySQL 的数据分片机制,会把每一个客户和全部相关的数据分配给一个固定的分区。这种布局方式,能够支持针对单个客户的 索引构建和复杂查询处理,可是,须要了解一些商业知识来设计分区。随着客户数量的增加, 对数据进行从新分区,代价是很大的。最近一次的从新分区,花费了两年的时间,为了下降风险,在多个团队之间进行了大量的合做和测试。这种操做太复杂了,没法经常执行,由此致使的结果是,团队必须限制 MySQL 数据库的增加,方法是,把一些数据存储在外部的 Bigtable 中,这就会牺牲事务和查询全部数据的能力。
F1 团队选择使用 Spanner 有几个方面的缘由。首先,Spanner 不须要手工分区。其次, Spanner 提供了同步复制和自动失败恢复。在采用 MySQL 的 master-slave 复制方法时,很难进行失败恢复,会有数据丢失和当机的风险。再次,F1 须要强壮的事务语义,这使得使用 其余 NoSQL 系统是不实际的。应用语义须要跨越任意数据的事务和一致性读。F1 团队也须要在他们的数据上构建二级索引(由于 Spanner 没有提供对二级索引的自动支持),也有能力使用 Spanner 事务来实现他们本身的一致性全球索引。
全部应用写操做,如今都是默认从 F1 发送到 Spanner。而不是发送到基于 MySQL 的应 用栈。F1 在美国的西岸有两个副本,在东岸有三个副本。这种副本位置的选择,是为了不发生天然灾害时出现服务中止问题,也是出于前端应用的位置的考虑。实际上,Spanner 的失败自动恢复,几乎是不可见的。在过去的几个月中,尽管有不在计划内的机群失效,可是,F1 团队最须要作的工做仍然是更新他们的数据库模式,来告诉 Spanner 在哪里放置 Paxos 领导者,从而使得它们尽可能靠近应用前端。
Spanner 时间戳语义,使得它对于 F1 而言,能够高效地维护从数据库状态计算获得的、放在内存中的数据结构。F1 会为全部变动都维护一个逻辑历史日志,它会做为每一个事务的 一部分写入到 Spanner。F1 会获得某个时间戳下的数据的完整快照,来初始化它的数据结构, 而后根据数据的增量变化来更新这个数据结构。
表 5 显示了 F1 中每一个目录的分片数量的分布状况。每一个目录一般对应于 F1 上的应用栈中的一个用户。绝大多数目录(同时意味着绝大多数用户)都只会包含一个分片,这就意味着,对于这些用户数据的读和写操做只会发生在一个服务器上。多于 100 个分片的目录,是那些包含 F1 二级索引的表:对这些表的多个分片进行写操做,是极其不寻常的。F1 团队也只是在以事务的方式进行未经优化的批量数据加载时,才会碰到这种情形。
表 6 显示了从 F1 服务器来测量的 Spanner 操做的延迟。在东海岸数据中心的副本,在 选择 Paxos 领导者方面会得到更高的优先级。表 6 中的数据是从这些数据中心的 F1 服务器 上测量获得的。写操做延迟分布上存在较大的标准差,是因为锁冲突引发的肥尾效应(fat tail)。在读操做延迟分布上存在更大的标准差,部分是由于 Paxos 领导者跨越了两个数据中心,只有其中的一个是采用了固态盘的机器。此外,测试内容还包括系统中的每一个针对两个 数据中心的读操做:字节读操做的平均值和标准差分别是 1.6KB 和 119KB。
Megastore[5]和 DynamoDB[3]已经提供了跨越多个数据中心的一致性复制。DynamoDB 提供了键值存储接口,只能在一个 region 内部进行复制。Spanner 和 Megastore 同样,都提供了半关系数据模型,甚至采用了相似的模式语言。Megastore 没法活动高性能。Megastore 是架构在 Bigtable 之上,这带来了很高的通信代价。Megastore 也不支持长寿命的领导者, 多个副本可能会发起写操做。来自不一样副本的写操做,在 Paxos 协议下必定会发生冲突,即便他们不会发生逻辑冲突:会严重影响吞吐量,在一个 Paxos 组内每秒钟只能执行几个写操做。Spanner 提供了更高的性能,通用的事务和外部一致性。
Pavlo 等人[31]对数据库和 MapReduce[12]的性能进行了比较。他们指出了几个努力的方向,能够在分布式键值存储之上充分利用数据库的功能[1][4][7][41],两者能够实现充分的融合。咱们比较赞同这个结论,而且认为集成多个层是具备优点的:把复制和并发控制集成起来,能够减小 Spanner 中的提交等待代价。
在一个采用了复制的存储上面实现事务,能够至少追述到 Gifford 的论文[16]。Scatter[17] 是一个最近的基于 DHT 的键值存储,能够在一致性复制上面实现事务。Spanner 则要比 Scatter 在更高的层次上提供接口。Gray 和 Lamport[18]描述了一个基于 Paxos 的非阻塞的提交协议,他们的协议会比两阶段提交协议带来更多的代价,而两阶段提交协议在大范围分布 式的组中的代价会进一步恶化。Walter[36]提供了一个快照隔离的变种,可是没法跨越数据中心。相反,咱们的只读事务提供了一个更加天然的语义,由于咱们对于全部的操做都支持外部语义。
最近,在减小或者消除锁开销方面已经有大量的研究工做。Calvin[40]消除了并发控制: 它会从新分配时间戳,而后以时间戳的顺序执行事务。HStore[39]和 Granola[11]都支持本身的事务类型划分方法,有些事务类型能够避免锁机制。可是,这些系统都没法提供外部一致性。Spanner 经过提供快照隔离,解决了冲突问题。
VoltDB[42]是一个分片的内存数据库,能够支持在大范围区域内进行主从复制,支持灾难恢复,可是没有提供通用的复制配置方法。它是一个被称为 NewSQL 的实例,这是实现 可扩展的 SQL[38]的强大的市场推进力。许多商业化的数据库均可以支持历史数据读取,好比 Marklogic[26]和 Oracle’ Total Recall[30]。Lomet 和 Li[24]对于这种时间数据库描述了一种 实现策略。
Faresite 给出了与一个受信任的时钟参考值相关的时钟不肯定性的边界13:Farsite 中的服务器租约的方式,和 Spanner 中维护 Paxos 租约的方式 相同。在以前的工做中[2][23],宽松同步时钟已经被用来进行并发控制。咱们已经展现了 TrueTime 能够从 Paxos 状态机集合中推导出全球时间。
在过去一年的大部分时间里,咱们都是 F1 团队一块儿工做,把谷歌的广告后台从 MySQL 迁移到 Spanner。咱们正在积极改进它的监控和支撑工具,同时在优化性能。此外,咱们已经开展了大量工做来改进备份恢复系统的功能和性能。咱们当前正在实现 Spanner 模式语言,自动维护二级索引和自动基于负载的分区。在将来,咱们会调研更多的特性。以最优化的方式并行执行读操做,是咱们追求的有价值的策略,可是,初级阶段的实验代表,实现这个目标比较艰难。此外,咱们计划最终能够支持直接变动 Paxos 配置[22]34]。
咱们但愿许多应用均可以跨越数据中心进行复制,而且这些数据中心彼此靠近。 TrueTime ε 可能会明显影响性能。把 ε 值下降到 1ms 之内,并不存在不可克服的障碍。 Time-master-query 间隔能够继续减小,Time-master-query 延迟应该随着网络的改进而减小, 或者经过采用分时技术来避免延迟。
最后,还有许多有待改进的方面。尽管 Spanner 在节点数量上是可扩展的,可是与节点相关的数据结构在复杂的 SQL 查询上的性能相对较差,由于,它们是被设计成服务于简单的键值访问的。来自数据库文献的算法和数据结构,能够极大改进单个节点的性能。另外,根据客户端负载的变化,在数据中心之间自动转移数据,已经成为咱们的一个目标,可是,为了有效实现这个目标,咱们必须具有在数据中心之间自动、协调地转移客户端应用进程的能力。转移进程会带来更加困难的问题——如何在数据中心之间管理和分配资源。
总的来讲,Spanner 对来自两个研究群体的概念进行告终合和扩充:一个是数据库研究群体,包括熟悉易用的半关系接口,事务和基于 SQL 的查询语言;另外一个是系统研究群体,包括可扩展性,自动分区,容错,一致性复制,外部一致性和大范围分布。自从 Spanner 概念成形,咱们花费了 5 年以上的时间来完成当前版本的设计和实现。花费这么长的时间,一部分缘由在于咱们慢慢意识到,Spanner 不该该仅仅解决全球复制的命名空间问题,并且也应该关注 Bigtable 中所丢失的数据库特性。
咱们的设计中一个亮点特性就是 TrueTime。咱们已经代表,在时间 API 中明确给出时钟不肯定性,能够以更增强壮的时间语义来构建分布式系统。此外,由于底层的系统在时钟不肯定性上采用更加严格的边界,实现更强壮的时间语义的代价就会减小。做为一个研究群体,咱们在设计分布式算法时,再也不依赖于弱同步的时钟和较弱的时间 API。
许多人帮助改进了这篇论文:Jon Howell,Atul Adya, Fay Chang, Frank Dabek, Sean Dorward, Bob Gruber, David Held, Nick Kline, Alex Thomson, and Joel Wein. 咱们的管理层对于咱们的工做和论文发表都很是支持:Aristotle Balogh, Bill Coughran, Urs H ̈olzle, Doron Meyer, Cos Nicolaou, Kathy Polizzi, Sridhar Ramaswany, and Shivakumar Venkataraman.
咱们的工做是在Bigtable和Megastore团队的工做基础之上开展的。F1团队,尤为是Jeff Shute ,和咱们一块儿工做,开发了数据模型,跟踪性能和纠正漏洞。Platforms团队,尤为是Luiz Barroso 和Bob Felderman,帮助咱们一块儿实现了TrueTime。最后,许多谷歌员工都曾经在咱们的团队工做过,包括Ken Ashcraft, Paul Cychosz, Krzysztof Ostrowski, Amir Voskoboynik, Matthew Weaver, Theo Vassilakis, and Eric Veach; or have joined our team recently: Nathan Bales, Adam Beberg, Vadim Borisov, Ken Chen, Brian Cooper, Cian Cullinan, Robert-Jan Huijsman, Milind Joshi, Andrey Khorlin, Dawid Kuroczko, Laramie Leavitt, Eric Li, Mike Mammarella, Sunil Mushran, Simon Nielsen, Ovidiu Platon, Ananth Shrinivas, Vadim Suvorov, and Marcel van der Holst.
[1] Azza Abouzeid et al. ―HadoopDB: an architectural hybrid of MapReduce and DBMS technologies for analytical workloads‖. Proc. of VLDB. 2009, pp. 922–933.
[2] A. Adya et al. ―Efficient optimistic concurrency control using loosely synchronized clocks‖. Proc. of SIGMOD. 1995, pp. 23–34.
[3] Amazon. Amazon DynamoDB. 2012.
[4] Michael Armbrust et al. ―PIQL: Success-Tolerant Query Processing in the Cloud‖. Proc. of VLDB. 2011, pp. 181–192.
[5] Jason Baker et al. ―Megastore: Providing Scalable, Highly Available Storage for Interactive Services‖. Proc. of CIDR. 2011, pp. 223–234.
[6] Hal Berenson et al. ―A critique of ANSI SQL isolation levels‖. Proc. of SIGMOD. 1995, pp. 1–10. [7] Matthias Brantner et al. ―Building a database on S3‖. Proc. of SIGMOD. 2008, pp. 251–264.
[7] Matthias Brantner et al. ―Building a database on S3‖. Proc. of SIGMOD. 2008, pp. 251–264.
[8] A. Chan and R. Gray. ―Implementing Distributed Read-Only Transactions‖. IEEE TOSE SE-11.2 (Feb. 1985), pp. 205–212.
[9] Fay Chang et al. ―Bigtable: A Distributed Storage System for Structured Data‖. ACM TOCS 26.2 (June 2008), 4:1–4:26.
[10] Brian F. Cooper et al. ―PNUTS: Yahoo!’s hosted data serving platform‖. Proc. of VLDB. 2008, pp. 1277–1288.
[11] James Cowling and Barbara Liskov. ―Granola: Low-Overhead Distributed Transaction Coordination‖. Proc. of USENIX ATC. 2012, pp. 223–236.
[12] Jeffrey Dean and Sanjay Ghemawat. ―MapReduce: a flexible data processing tool‖. CACM 53.1 (Jan. 2010), pp. 72–77.
[13] John Douceur and Jon Howell. Scalable Byzantine-Fault-Quantifying Clock Synchronization. Tech. rep. MSR-TR-2003-67. MS Research, 2003.
[14] John R. Douceur and Jon Howell. ―Distributed directory service in the Farsite file system‖. Proc. of OSDI. 2006, pp. 321–334.
[15] Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung. ―The Google file system‖. Proc. of SOSP. Dec. 2003, pp. 29–43.
[16] David K. Gifford. Information Storage in a Decentralized Computer System. Tech. rep. CSL-81-8. PhD dissertation. Xerox PARC, July 1982.
[17] Lisa Glendenning et al. ―Scalable consistency in Scatter‖. Proc. of SOSP. 2011.
[18] Jim Gray and Leslie Lamport. ―Consensus on transaction commit‖. ACM TODS 31.1 (Mar. 2006), pp. 133–160.
[19] Pat Helland. ―Life beyond Distributed Transactions: an Apostate’s Opinion‖. Proc. of CIDR. 2007, pp. 132–141.
[20] Maurice P. Herlihy and Jeannette M. Wing. ―Linearizability: a correctness condition for
concurrent objects‖. ACM TOPLAS 12.3 (July 1990), pp. 463–492.
[21] Leslie Lamport. ―The part-time parliament‖. ACM TOCS 16.2 (May 1998), pp. 133–169.
[22] Leslie Lamport, Dahlia Malkhi, and Lidong Zhou. ―Reconfiguring a state machine‖. SIGACT News 41.1 (Mar. 2010), pp. 63–73.
[23] Barbara Liskov. ―Practical uses of synchronized clocks in distributed systems‖. Distrib. Comput. 6.4 (July 1993), pp. 211–219.
[24] David B. Lomet and Feifei Li. ―Improving Transaction-Time DBMS Performance and Functionality‖. Proc. of ICDE (2009), pp. 581–591.
[25] Jacob R. Lorch et al. ―The SMART way to migrate replicated stateful services‖. Proc. of EuroSys. 2006, pp. 103–115.
[26] MarkLogic. MarkLogic 5 Product Documentation. 2012.
[27] Keith Marzullo and Susan Owicki. ―Maintaining the time in a distributed system‖. Proc. of PODC. 1983, pp. 295–305.
[28] Sergey Melnik et al. ―Dremel: Interactive Analysis of Web-Scale Datasets‖. Proc. of VLDB. 2010, pp. 330–339.
[29] D.L. Mills. Time synchronization in DCNET hosts. Internet Project Report IEN–173. COMSAT Laboratories, Feb. 1981.
[30] Oracle. Oracle Total Recall. 2012.
[31] Andrew Pavlo et al. ―A comparison of approaches to large-scale data analysis‖. Proc. of SIGMOD. 2009, pp. 165–178.
[32] Daniel Peng and Frank Dabek. ―Large-scale incremental processing using distributed transactions and notifications‖. Proc. of OSDI. 2010, pp. 1–15.
[33] Daniel J. Rosenkrantz, Richard E. Stearns, and Philip M. Lewis II. ―System level concurrency control for distributed database systems‖. ACM TODS 3.2 (June 1978), pp. 178–198.
[34] Alexander Shraer et al. ―Dynamic Reconfiguration of Primary/Backup Clusters‖. Proc. of
SENIX ATC. 2012, pp. 425–438.
[35] Jeff Shute et al. ―F1—The Fault-Tolerant Distributed RDBMS Supporting Google’s Ad Business‖. Proc. of SIGMOD. May 2012, pp. 777–778.
[36] Yair Sovran et al. ―Transactional storage for geo-replicated systems‖. Proc. of SOSP. 2011, pp. 385–400.
[37] Michael Stonebraker. Why Enterprises Are Uninterested in NoSQL. 2010.
[38] Michael Stonebraker. Six SQL Urban Myths. 2010.
[39] Michael Stonebraker et al. ―The end of an architectural era: (it’s time for a complete rewrite)‖. Proc. of VLDB. 2007, pp. 1150–1160.
[40] Alexander Thomson et al. ―Calvin: Fast Distributed Transactions for Partitioned Database Systems‖. Proc. of SIGMOD.2012, pp. 1–12.
[41] Ashish Thusoo et al. ―Hive — A Petabyte Scale Data Warehouse Using Hadoop‖. Proc. of ICDE. 2010, pp. 996–1005.
[42] VoltDB. VoltDB Resources. 2012.
欢迎进入博客 :linbingdong.com 获取最新文章哦~
欢迎关注公众号: FullStackPlan 获取更多干货哦~