您的位置:首页 > 编程语言 > Go语言

《Spanner: Google’s Globally-Distributed Database》论文总结

2020-08-06 22:45 1326 查看
# Spanner 总结 **说明**:本文为论文 **《Spanner: Google’s Globally-Distributed Database》** 的个人理解,难免有理解不到位之处,欢迎交流与指正 。 **论文地址**:[Spanner Paper](https://github.com/XutongLi/Learning-Notes/blob/master/Distributed_System/Paper_Reading/Spanner/spanner.pdf) *** ## 0. 简介 **Spanner** 是由 *Google* 设计和研发的一款分布式数据库。它将数据分布在全球范围内,并支持外部一致性的分布式事务。对于读写事务,它使用基于 *Paxos* 复制容错的 *2PC* ;对于只读事务,它不使用锁机制,且允许从本地副本执行读操作,从而提高了只读事务处理效率。 *** ## 1. 结构 ### 1.1 Spanner 服务器组织 ![](https://img2020.cnblogs.com/blog/2035097/202008/2035097-20200806224139024-497058813.png) - 一个 **Spanner** 部署称为一个 **universe** - *Spanner* 被组织成许多个 **zone** 的集合 - **zone** 是管理部署的基本单元,当新的数据中心加入服务、或者老的数据中心被关闭时,*zone* 可以被加入到一个运行的系统中,或从中移除。*zone* 也是物理隔离的单元,在一个数据中心中可能有一个或多个 *zone*(当属于不同应用的数据必须被分区存储到同一数据中心的不同服务器集合中时,一个数据中心就会有多个 *zone*)。 - 一个 *zone* 包含一个 **zonemaster** 和多个 **spanserver** - **zonemaster** 把数据分配给 **spanserver** ,**spanserver** 把数据提供给客户端 - 客户端使用每个 *zone* 上面的 **location proxy** 来定位可以为自己提供数据的 **spanserver** - **universemaster** 主要是一个控制台,它显示了关于 *zone* 的各种状态信息,可用于相互之间的调试 - **placement driver** 会周期性地与 **spanserver** 进行交互,来发现那些需要被转移的数据(或是为了满足新的副本约束条件、或是为了进行负载均衡) ### 1.2 SpanServer 构成 ![](https://img2020.cnblogs.com/blog/2035097/202008/2035097-20200806224146242-665703150.png) - 在底部,每个 **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* 中的 *leader* 为 **participant leader**,其他副本为 **participant slave** ;如果一个事务包含了多个 *Paxos Group* ,其中一个 *Paxos Group* 会被选为 **coordinator** ,该组 *leader* 为 **coordinator leader** ,该组其他副本为 **coordinator slaves** (这些设置是为了支持 *two phase commit*)。 ### 1.3 目录 *Spanner* 支持 **目录**,它是包含公共前缀的连续键的集合。对目录的支持,可以让应用通过选择合适的键来控制数据的局部性。 一个目录是数据放置的基本单元,属于一个目录的所有数据都具有相同的副本配置。当数据在不同的 *Paxos Group* 之间移动时,会一个目录一个目录地转移。 ![](https://img2020.cnblogs.com/blog/2035097/202008/2035097-20200806224153875-492469942.png) *** ## 2. 分布式事务 ### 2.1 读写事务 读写事务的提交,采用 **基于Paxos的两阶段提交 (2PC)** 。 以下述事务为例: ``` BEGIN: x = x + 1 y = y - 1 END ``` ![](https://img2020.cnblogs.com/blog/2035097/202008/2035097-20200806224202777-988561656.png) 上图中一个黄色矩形框为一个 *Data Shard* 的 *Paxos Group* ,每个绿圈为一个副本,存储在不同的 *Data Center* 。黑色矩形框中的副本为各 *Paxos Group* 中的 *leader* 。 上述读写事务的执行过程为(过程与图中序号对应): 0. *client* 为每个事务设置一个事务 *ID* (*TID*) 1. *client* 发送读操作给到 *X* 和 *Y* 所在 *Paxos Group* 的 *leader*。读操作执行前要先获得对应记录的锁,锁由 *lock table* 提供 2. 两个 *leader* 返回 *X* 和 *Y* 的当前值给 *client* 3. 提交前,先选择一个 *Paxos Group* 作为*2PC* 的 *transaction coordinator (TC)* (图中红框即为 *TC leader*),其余 *Paxos Group* 为 *transaction participant (TP)*。接着,*client* 发送写操作给两个 *Paxos Group* 的 *leader* 4. 每个 *leader* 获取对应记录的锁,通过 *Paxos* 在 *Paxos Group* 中记录 `PREPARE` 5. 如果记录好`PREPARE`,各 *leader* 回复 *TC* `YES` ;若出现故障,恢复 *TC* `NO` 6. *TC* 接收到所有 *TP leader* 的回复之后,决定是提交还是中断。将决定通过 *Paxos* 记录在本 *Paxos Group* 的 *log* 中,发送 `COMMIT` 通知给所有 *TP leader* 7. 每个 *TP leader* 通过 *Paxos* 将 *TC* 的决定记录在 *log* 中,之后释放占用的锁 ### 2.2 只读事务 只读事务可能包含多个读操作,读取数据可能位于多个 *Paxos Group* ,但不包含写操作。 因为只读事务占比比较大,所以希望只读操作执行更快。 对于只读事务,*Spanner* 进行了两个方面的优化:**允许从本地副本读取** 和 **不使用锁、2PC、事务管理器** 。 #### 2.2.1 允许从本地副本读取 *Spanner* 允许 *client* 从本地副本读取数据,这样就避免了很多 *Paxos* 以及 *data center* 之间的通信,可以加快只读事务的处理速度。 但是本地副本可能不是最新的(由于 *Paxos* 的 *majority* 机制),为解决这个问题,使用 **safe time**: - 每个副本都会跟踪记录一个值,称为 *safe time* ($t_{safe}$),它是一个副本最近更新后的最大时间戳 - 如果一个读操作的时间戳是 $t$ ,当满足 $t
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: