Spanner 总结

说明:本文为论文 《Spanner: Google’s Globally-Distributed Database》 的个人理解,难免有理解不到位之处,欢迎交流与指正 。

论文地址Spanner Paper


0. 简介

Spanner 是由 Google 设计和研发的一款分布式数据库。它将数据分布在全球范围内,并支持外部一致性的分布式事务。对于读写事务,它使用基于 Paxos 复制容错的 2PC ;对于只读事务,它不使用锁机制,且允许从本地副本执行读操作,从而提高了只读事务处理效率。


1. 结构

1.1 Spanner 服务器组织

  • 一个 Spanner 部署称为一个 universe

  • Spanner 被组织成许多个 zone 的集合

  • zone 是管理部署的基本单元,当新的数据中心加入服务、或者老的数据中心被关闭时,zone 可以被加入到一个运行的系统中,或从中移除。zone 也是物理隔离的单元,在一个数据中心中可能有一个或多个 zone(当属于不同应用的数据必须被分区存储到同一数据中心的不同服务器集合中时,一个数据中心就会有多个 zone)。

  • 一个 zone 包含一个 zonemaster 和多个 spanserver

  • zonemaster 把数据分配给 spanserverspanserver 把数据提供给客户端

  • 客户端使用每个 zone 上面的 location proxy 来定位可以为自己提供数据的 spanserver

  • universemaster 主要是一个控制台,它显示了关于 zone 的各种状态信息,可用于相互之间的调试

  • placement driver 会周期性地与 spanserver 进行交互,来发现那些需要被转移的数据(或是为了满足新的副本约束条件、或是为了进行负载均衡)

1.2 SpanServer 构成

  • 在底部,每个 spanserver 负载管理100-1000个称为 tablet 的数据结构的实例, tablet 实现映射:(key:string, timestamp:int64)->string
  • tablet 的状态会被存储到 Colossus 分布式文件系统中
  • 为了支持复制,每个 spanserver 会在每个 tablet 上面实现一个单个的 Paxos 状态机,每个状态机都会在相应的 tablet 中保存自己的元数据和日志
  • 副本的集合被称为 Paxos Group ,即一个数据分片(shard)对应一个 Paxos Group
  • 写操作要从 Paxos leader 开始执行,读操作可以从足够新的副本中直接执行
  • 对于每个是 leader 的副本而言,每个 spanserver 会实现一个 lock table 来实现并发控制
  • 对于每个是 ledaer 的副本而言,每个 spanserver 会实现一个 transaction manager 来支持分布式事务。Paxos Group 中的 leaderparticipant leader,其他副本为 participant slave ;如果一个事务包含了多个 Paxos Group ,其中一个 Paxos Group 会被选为 coordinator ,该组 leadercoordinator leader ,该组其他副本为 coordinator slaves (这些设置是为了支持 two phase commit)。

1.3 目录

Spanner 支持 目录,它是包含公共前缀的连续键的集合。对目录的支持,可以让应用通过选择合适的键来控制数据的局部性。

一个目录是数据放置的基本单元,属于一个目录的所有数据都具有相同的副本配置。当数据在不同的 Paxos Group 之间移动时,会一个目录一个目录地转移。


2. 分布式事务

2.1 读写事务

读写事务的提交,采用 基于Paxos的两阶段提交 (2PC)

以下述事务为例:

BEGIN:
x = x + 1
y = y - 1
END

上图中一个黄色矩形框为一个 Data ShardPaxos Group ,每个绿圈为一个副本,存储在不同的 Data Center 。黑色矩形框中的副本为各 Paxos Group 中的 leader

上述读写事务的执行过程为(过程与图中序号对应):

  1. client 为每个事务设置一个事务 IDTID
  2. client 发送读操作给到 XY 所在 Paxos Groupleader。读操作执行前要先获得对应记录的锁,锁由 lock table 提供
  3. 两个 leader 返回 XY 的当前值给 client
  4. 提交前,先选择一个 Paxos Group 作为2PCtransaction coordinator (TC) (图中红框即为 TC leader),其余 Paxos Grouptransaction participant (TP)。接着,client 发送写操作给两个 Paxos Groupleader
  5. 每个 leader 获取对应记录的锁,通过 PaxosPaxos Group 中记录 PREPARE
  6. 如果记录好PREPARE,各 leader 回复 TC YES ;若出现故障,恢复 TC NO
  7. TC 接收到所有 TP leader 的回复之后,决定是提交还是中断。将决定通过 Paxos 记录在本 Paxos Grouplog 中,发送 COMMIT 通知给所有 TP leader
  8. 每个 TP leader 通过 PaxosTC 的决定记录在 log 中,之后释放占用的锁

2.2 只读事务

只读事务可能包含多个读操作,读取数据可能位于多个 Paxos Group ,但不包含写操作。

因为只读事务占比比较大,所以希望只读操作执行更快。

对于只读事务,Spanner 进行了两个方面的优化:允许从本地副本读取不使用锁、2PC、事务管理器

2.2.1 允许从本地副本读取

Spanner 允许 client 从本地副本读取数据,这样就避免了很多 Paxos 以及 data center 之间的通信,可以加快只读事务的处理速度。

但是本地副本可能不是最新的(由于 Paxosmajority 机制),为解决这个问题,使用 safe time

  • 每个副本都会跟踪记录一个值,称为 safe time (\(t_{safe}\)),它是一个副本最近更新后的最大时间戳
  • 如果一个读操作的时间戳是 \(t\) ,当满足 \(t<=t_{safe}\) 时,这个副本就可以被这个读操作读取

2.2.2 不使用锁、2PC和事务管理器

Spanner 支持不加锁的只读事务,这一特性同样避免了很多 Paxos 以及 data center 之间的通信,并且不会减慢读写事务的处理。

对于不加锁的只读事务,为保证正确性,必须满足:

  • 可序列化:虽然多个事务会并发执行,但是执行结果等同于它们按照一定顺序逐一执行的结果
  • 外部一致性:如果 T1T2 开始前提交,则 T2 必须看到 T1 写操作的结果。

保证正确性的方法是采用 快照隔离 (Snapshot Isolation)

  • 首先同步所有服务器的时钟
  • 为每一个事务设置一个时间戳
    • 读写事务:以提交开始时间作为时间戳
    • 只读事务:以事务开始时间作为时间戳
  • 事务并发执行的效果与以时间戳顺序逐一执行的效果相同
  • 每个副本对于每条记录都存储多个时间戳版本,所有读写事务的写操作都是相同的时间戳
  • 只读事务能看到本事务时间戳之前的数据版本

3. TrueTime

由上述内容可以看到,时间戳在 Spanner 中起到了一个很重要的作用。但是如果不同服务器上的时钟不同步,则可能导致一些问题:

  • 如果一个只读事务的时间戳过大,会导致它的时间戳大于副本的 safe time ,读操作就会阻塞
  • 如果一个只读事务的时间戳过小,会漏读一些在该事务准确时间戳之前提交的数据版本(即读到的数据是过期的),这样违背了外部一致性

为进行时间同步,Spanner 在每个 data center 设置一些 time master server 。每个 time master 含有一个 GPS receiver 或一个 atomic clock 。其他 server 会从几个 time master server 中收集投票,获得时间参考值,从而减少误差。但是由于网络延迟原因,得到的时间也会有一定幅度偏移(时间不确定性问题)。

针对时间不确定性问题,Spanner 提供了一个 TrueTime API ,它将时间显示表达为 TTinterval ,它是一个时间区间,具有有界限的时间不确定性,保证了当前准确时间在这个区间里。TTinterval 的端点是 TTstamp 类型。API 提供了三个方法:

为保证 外部一致性Spanner 设定了两条规则:

  • Start rule:设事务时间戳为 TT.now().lastest。对于读写事务,TT 为开始提交的时间戳;对于只读事务,TT 为事务开始时间。
  • Commit wait:对于读写事务,延迟到 TS < TS.now().earliest 时再提交,保证事务时间戳TS 已经完全过去。

6. 特点

  1. 数据分片存储在跨越全球的 Paxos 状态机上,通过并发访问来提高吞吐量
  2. Spanner 提供了读和写操作的外部一致性,以及在一个时间标准下的全球一致性的读操作
  3. 随着数据变化和服务器变化,Spanner 可以自动对数据进行重新分片,以进行负载均衡和失败处理
  4. 应用可以对数据的副本进行控制,如指定哪些数据中心包含哪些数据
  5. Spanner 可以为事务分配全球范围内有意义的提交时间戳,这些时间戳反映事务序列化的顺序,用以满足外部一致性的要求
  6. 提出了 TrueTime APISpanner 时间戳的保证就是取决于这个 API 的界限
  7. 只读事务不采用锁机制,且可以从最新副本上直接读取数据。由于只读事务占比大,因此显著提升了事务处理效率

5. 和 Aurora 的比较

Spanner Aurora
架构 Shared Nothing Shared Disk
可用性 Paxos-based Quorum-based
写扩展 T F
分库分表透明性 T F
分布式事务 T F
MySQL/Postgres兼容性 F T

Aurora:主要用于云上业务,兼容 MySQL/PostgresSQL。通过共享存储方案避免了二阶段提交、分布式事务等复杂的实现,因此开发周期较短。

Spanner:是一种重新设计的数据库,基于 Paxos 的强同步、对分布式事务的支持以及利用 TrueTime 机制实现的全局一致性读都是比较强大的功能。但是对 SQL 的兼容性不够好。


《Spanner: Google’s Globally-Distributed Database》论文总结的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. python 装饰器(八):装饰器基础(四)types.MethodType的作用

    1 types.MethodType的作用—添加实例方法 import types class cla(object): def __init__(self, name, age): self.nam ...

  2. python技巧 namedtuple

    python的namedtuple可以创建一个带字段名的元祖和一个带名字的类 In [1]: from collections import namedtuple ...: ...: nginx=na ...

  3. JavaScript:父页面与Iframe页面方法互调

    父页面调用Iframe页面中的函数 以上是父页面中定义的iframe,注意添加name属性 在父页面中调用mapFrame的ShowMyLocation方法 Iframe页面调用父页面的方法 直接在I ...

  4. 05-Python模块

    一.简介 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py.模块可以被其他程序导入来使用模块具有的功能.这也是使用python标准库的方式. import time start_time ...

  5. 德布鲁因序列与indexing 1

    目录 写在前面 标记left-most 1与right-most 1 确定位置 德布鲁因序列(De Bruijn sequence) 德布鲁因序列的使用 德布鲁因序列的生成与索引表的构建 参考 博客: ...

  6. day6 python while,for 循环控制

    1.1双向循环控制流程 i = 0 while i > 10: #外层循环 j = 10 while j < 0: #内层循环 j -= 1 i += 1 1.1.1 双向循环练习---- ...

  7. 阿里面试官:这些软件测试面试题都答对了,I want you!

    [ 你悄悄来,请记得带走一丝云彩 ] 测试岗必知必会 01请描述如何划分缺陷与错误严重性和优先级别? 给软件缺陷与错误划分严重性和优先级的通用原则: 1. 表示软件缺陷所造成的危害和恶劣程度. 2. ...

  8. Windows 磁盘分区后如何再合并&如何用Windows自带工具扩大某个分区

    Windows 磁盘分区后如何再合并&用Windows自带工具扩大某个分区 注:此方法有一定的成功率,更加完善可行的方法请看http://www.diskgenius.cn/help/part ...

  9. java实现判断时间是否为合法时间

    最近遇到一个需求,输入字符串,判断为日期的话再进行后面的比较大小之类的操作,但是合法日期的格式也是比较多的,利用正则表达式又太长了.所以后面利用的方法就是,先把输入的字符串转成一种固定的时间格式,然后 ...

  10. Ethical Hacking - NETWORK PENETRATION TESTING(12)

    Post Connection Attacks Sophisticated attacks that can be used after connecting to the target AP. Ga ...