前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分析 Google Cloud Spanner 的架构

分析 Google Cloud Spanner 的架构

作者头像
哒呵呵
发布2020-02-19 15:04:17
3.4K0
发布2020-02-19 15:04:17
举报
文章被收录于专栏:鸿的学习笔记

本文来源于 https://thedataguy.in/internals-of-google-cloud-spanner/。这篇是目前看过解析 Spanner 的内部机制最好的文章。

MySQL的痛苦

在2005、2006年期间,谷歌内部大规模使用了 MySQL 数据库。其中Google Adwords (谷歌广告部门)使用了 90 多个 MySQL Shards(分片)集群方案存储数据,是谷歌内部使用 MySQL 数据库的最大的部门之一。由于系统维护的原因,谷歌广告部门重新规划了 MySQL 集群,整个过程花了 2 年时间。因为谷歌知道它们的数据增长的非常快,再使用 MySQL 这类数据库到未来的某个时刻会非常痛苦。这就是 Spanner 的诞生原因。

BigTable和Spanner

因为 BigTable 团队本身就在做分布式系统的工作,比如存储和高可用性(或者可能还有其他原因),所以当谷歌决定构建新的分布式系统时,BigTable 团队便成了 Spanner 的开发团队。

Colossus

Colossus 是从 GFS 演化而来的分布式文件系统。一个厉害的数据库需要一个高性能的文件系统支持。Colossus 项目由 BigTable 团队发起的,并且 Colossus 也为 BigTable 提供了支持。因此,Spanner 也成为了文件系统 Colossus 的使用方。

为什么要做 Spanner ?

谷歌广告部门一直以来都使用 MySQL 数据库作为其基础设施,并且它们还是 SQL 语言的爱好者。谷歌广告部门希望使用 SQL 去处理业务问题,而且要处理有关钱的问题,因此新系统必须要支持 ACID 事务。使用 MySQL 的痛苦在于重新分片,所以新系统需要像传统 NoSQL 一样支持自动分片和热点数据再平衡。另外,高可用、水平拓展和支持全世界分布也是必须的。

Spanner的架构

Spanner 是分布在全世界各个地方的数据库系统,每个 region 至少存在 3 个分片( shard )。每个 zone 中至少有一个分片。在 Spanner 中,分片被称为 Split 。如果在 Spanner 集群中你看见了一个节点(Node),那么至少不同的 zone 中存在另外2个对你不可见的节点(Node)。Spanner 的设计中,计算层和存储层是分离的;并且使用 Paxos 算法保证只有一个 Leader ,其余节点都是 Follower。

基于数据分区的理念,Spanner 在存储层中会将数据打散成很多的分片( Split )。每个分片都会被复制到其他 zone 中。例如:如果您在 A 区上有一个名为 S1 的分片,那么它将会被复制到 B 区和 C 区。复制使用的是主从模式。因此,Paxos 算法会保证 Leader 的选举正常进行,并在某个 Leader 宕机的期间选择新的 Leader 。如果客户端需要在某个 Split 上写入数据时,通过 Spanner API 首先会知道 Leaders ,再将写入的数据直接转到对应的 zone 中。每个 Split 都有自己的 Leader zone 。

全球强一致性

Spanner 的重点就是强一致性。Spanner 支持所有节点之间的强一致性(全局)。如果您在美国地区写入某条数据,那在亚洲地区或任何其他地区都能读取到相同的数据。Spanner 是如何实现这种逻辑?这个黑科技称为 TrueTime 。

TrueTime

Spanner 会经常进行数据同步,并且全球所有数据中心内的所有节点上都会保持相同的时间。节点使用的硬件内置了原子钟以保证时间的可靠性。在放置服务器的机架中,会有4个时间服务器。2台服务器负责与GPS连接,其余2台与 Automic Oscillators(原子振荡器)连接。使用 2 个不同品牌的原子振荡器,可以更好地进行故障转移。GPS 时间服务器会每隔 30 秒去和原子振荡器同步全球数据中心的时间。

使用 TrueTime 保证强一致性

要了解一致性和 TrueTime 之间的关系,我们必须了解在 Spanner 中如何执行写操作。在每次写操作期间,Spanner 会获得当前的 TrueTime 值,并且使用这个 TrueTime 时间戳为写操作创建一个序号(为了保证顺序),每次提交都会附带时间戳。

例如:如果要在节点 1 上写数据,它将使用 TrueTime 时间戳提交数据,并将数据和时间戳复制到其他节点。在所有节点上,这个时间戳都是相同。假设我们在节点A上提交了此数据,此时你正在从节点B读取相同的数据,那么 Spanner API 会向 Split 的 Leader 询问最后提交的数据的时间戳,如果此时间戳与节点A的时间戳相一致,那么节点B返回数据,否则 Spanner API 会一致到节点A将数据同步到节点B,然后再返回数据。

单条数据的写操作的生命周期

下图是单行写操作的生命周期。客户端将在 Split 2 写入一条数据。

  1. 首先,Spanner API 从元数据中获得谁是 Split 2 的 Leader 节点;
  2. 然后,请求进入 Zone B 节点(蓝色表示是Leader);
  3. 再然后,获取锁并将这条数据写入 Split 中,写入完成后,它将请求发送到 Zone A 和 C 节点再次进行写入;
  4. 最后,Leader 会等待大多数节点的确认这条数据已经写入。
  5. Leader 一旦获得了大部分 Follower 的确认已写入信息,便会将成功响应发送给客户。
多条数据的写操作的生命周期

如果要在单个事务中写入数据,但这些数据位于不同的 Split 中,则 Spanner 会以不同的方式处理这些数据。例如:我们需要更新2行数据。

  1. 第1行在 Split1 - Zone C 中,是 Leader Split
  2. 第2行在 Split2 - Zone B 中,是 Leader Split

当我们启动事务时,Spanner API 会明白这些行是处于不同的 Split 中。于是 Spanner API 随机选择一个协调(Co-ordinator) zone。在示例中,Spanner API 选择了 Zone C 为协调 zone。然后会执行以下步骤:

  1. 选择协调 zone。(Zone C)
  2. 同时获取两个 Leader Split 上的数据锁。
  3. 将新数据写入到两个 Leader Split 中。Leader Split 会将新数据复制到 Follower Split 中。然后 Leader Split 会一直等待,直到获得 Follower Split 的确认(两个 Split 都会等待,直到获得 Follower Split 的确认)。
  4. 然后,Zone B 的 Split 将向 协调 zone 的 Split 发送一条消息,表明已完成更新并准备提交(commit)数据。
  5. 再然后,Zone C 中的 Split1 将会通知 Split2 ,继续并提交数据。同时,Split1 也将提交数据。
  6. 提交请求将转到所有的 Split(包括 Leader 和 follower)中,并永久提交数据。
  7. 然后,将成功响应将返回给客户端。
读操作的生命周期

从 Spanner 读取数据时,会最近的 Follower Split 中获取数据。下图是示例:

客户端想从 MyTable 中读取 Key 为123的数据。这个数据存储在 Split 2 中。一旦请求到达 Spanner Frontend 服务器,服务器会知道谁是最近的 Follower Split 并将请求转发到该 Split 中。在这条示例中,Zone A是最近的 Split 。请求到达 Split 后,该 Split 将请求 Leader Split 以获取最后提交的 TrueTime 值;然后,该 Split 将时间戳与自己的时间戳进行比较:如果两者都匹配,数据将返回给应用程序。如果时间戳不匹配,则 Leader Split 要求 Follower 等待,直到将数据同步到该区域,此时 Split 再提供服务。

读取操作过期或者是有时间限制的读取操作

Spanner 支持 MVCC (多版本并发控制)。因此,Spanner 会将旧数据保留一段时间。如果应用程序对于拿到旧数据(X 秒前的)没有任何影响,则无需等待 Leader Split 的数据同步。例如,应用程序告诉 Split 使用15秒前的旧数据就可以了,然后 Split 会检查已提交数据的时间戳,该时间戳如果少于15秒,就会将旧数据提供给应用程序。

多区域( region )下的 Spanner

到目前为止,讨论的都是单区域( region )内的操作方案(仅 zone 级别),但是 Spanner 是为了可以扩展到多个区域( region )而构建的。在多区域( region )情况下,架构和写/读操作与之前略有不同。在单区域( region )概念中,至少需要3个 zone 才能创建集群,并且 zone 同时支持读取和写入。但是在多区域( region )概念中,一个 Continent 将充当 Leader ,而其他 Continent 将成为 Follower 。用 Spanner 的话来说,拥有更多 region 的 Continent 内部会拥有选举权限。所有写操作都会到达 Continent 的任意区域( region )中。在进行选举的 Continent 中,会有2个区域( region )负责数据节点,而1个区域( region )将负责监控服务器状态,并及时进行故障转移。其他 Continent 只有只读副本节点。

多区域( region )下的数据一致性

在多区域( region )概念中,写入操作总是发生在执行 Quorum Continent 上。在上一段中,美国 Continent 是负责读写的 Continent ,那么如果客户端从美国发送写请求,则 Spanner API 会将其发送到最近的区域( region ),一旦提交了数据,则成功响应返回给客户端。如果客户端要从亚洲发送写请求,则亚洲 Continent 的 API 服务器会将请求放入 Google 的内部网络中,然后再将请求发送到美国 Continent 的API服务器。然后,该美国区域( region )API服务器将提交数据,并将成功响应返回给亚洲客户。

对于读取,过程与单个区域( region )的读取过程相同,如果 TrueTime 匹配,则将从本地区域( region )提供数据,否则将等待直到数据同步到本地区域( region )然后再提供给客户端。

总结

以上就是这篇文章的所有内容了,希望这篇翻译能覆盖到所有的 Spanner 的概念。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MySQL的痛苦
  • BigTable和Spanner
  • Colossus
  • 为什么要做 Spanner ?
  • Spanner的架构
  • 全球强一致性
    • TrueTime
    • 使用 TrueTime 保证强一致性
    • 单条数据的写操作的生命周期
    • 多条数据的写操作的生命周期
    • 读操作的生命周期
    • 读取操作过期或者是有时间限制的读取操作
    • 多区域( region )下的 Spanner
    • 多区域( region )下的数据一致性
    • 总结
    相关产品与服务
    云数据库 SQL Server
    腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档