对于每个扮演领导者角色的副本,每个 spanserver 也会实施一个事务管理器来支持分布式事务。这个事务管理器被用来实现一个 participant leader,该组内的其他副本则是作为 participant slaves。如果一个事务只包含一个 Paxos 组(对于许多事务而言都是如此),它就可以绕过事务管理器,因为锁表和 Paxos 二者一起可以保证事务性。如果一个事务包含了多 于一个 Paxos 组,那些组的领导者之间会彼此协调合作完成两阶段提交。其中一个参与者组,会被选为协调者,��组的 participant leader 被称为 coordinator leader,该组的 participant slaves 被称为 coordinator slaves。每个事务管理器的状态,会被保存到底层的 Paxos 组。
2.2 目录和放置在一系列键值映射的上层,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 在不同组之间转移的是分片,而不是转移整个目录。
2.3 数据模型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 上运行两阶段提交弱化了可用性问题。