论文地址:F1:可扩展的分布式SQL数据库

    近年来,工程界的传统观点是,如果您需要一个高度可伸缩的、高吞吐量的数据存储,唯一可行的选择是使用NoSQL键/值存储,并解决缺少ACID事务保证和缺少辅助索引、SQL等便利性的问题。当我们为AdWords产品寻找Google MySQL数据存储的替代品时,这个选项根本不可行:在业务逻辑的每个部分处理非ACID数据存储的复杂性都太大了,如果没有SQL查询,我们的业务根本无法正常运行。
    这是F1的故事,谷歌建立了这个数据库来运行他们的广告业务。在本系列之前,我们还研究了Photon,即支持同一系统的分布式流连接解决方案。
    我喜欢这篇文章不仅仅是为了描述F1数据库是如何构建的,还为了讨论为什么它是这样的,以及系统设计决策对用户(开发人员)的影响是如何考虑的。让我们从一些非常有力的词开始:
    我们[也]在谷歌的最终一致性系统方面有很多经验。在所有这样的系统中,我们发现开发人员花了很大一部分时间构建极其复杂且容易出错的机制,以处理最终的一致性并处理可能过时的数据。我们认为这对开发人员来说是一个不可接受的负担,应该在数据库级别解决一致性问题。完全事务一致性是F1最重要的特性之一。

    设计应用程序以处理其数据中的并发异常非常容易出错、耗时,而且最终不值得获得性能收益。

    关键设计标准是:

    • 只需添加资源即可实现可伸缩性。不需要手工扩展和再扩展。
    • 可用性(这是谷歌的核心业务系统)
    • 一致性——完整的ACID事务,应用程序开发人员无需处理不一致的问题
    • 易用性——完整的SQL查询支持和SQL数据库所需的其他功能。“索引和特别查询等功能不仅很好,而且对我们的业务有绝对的要求。

    最近的出版物表明,这些设计目标是相互排斥的。本文的一个重要贡献是展示了我们是如何在F1的设计中实现所有这些目标的,以及我们在哪里做出了权衡和牺牲。
    F1构建在Spanner之上用于数据存储,并接受更高的典型读写延迟,以提供一致性。这种延迟通过显式集群和大量使用批处理、并行性和异步读取得到改善,从而使面向用户的事务的总体性能达到与以前基于MySQL的系统相同的水平。
    要了解F1的设计规模,请考虑(AdWords)数据库容量超过100tb,每秒可处理数十万个请求,并运行每天扫描数万亿数据行的SQL查询。
    这篇论文有很多,这使得总结起来很难做到公正。F1的一些特点包括:

    • 层次结构模式——通过该模式,可以将表组织为一个层次结构,其中子表行与父表的行一起存储,并在父表的行中交错。以聚合实体为例。仅限于单个根的事务通常避免2PC和相关的延迟。
    • 表列可以包含结构化数据类型,特别是协议缓冲区。

    在Google,协议缓冲区对于应用程序之间的数据存储和交换是无处不在的。当我们仍然使用MySQL模式时,用户常常不得不在数据库行和内存中的数据结构之间编写冗长且容易出错的转换。将协议缓冲区放在模式中可以消除这种阻抗不匹配,并为用户提供一个通用的数据结构,用户可以在数据库和应用程序代码中使用…。协议缓冲区列更加自然,并降低了用户的语义复杂性,用户现在可以将逻辑业务对象作为原子单元读写,而不必考虑使用跨多个表的连接将它们具体化

    • 交易性和完全一致性指数,分为本地指数和全球指数。
    • 支持完全无阻塞的模式更改

    AdWords数据库被成千上万的用户共享,并且正在不断开发中。开发人员将成批的模式更改排队并每天应用。这个数据库对Google来说至关重要,需要非常高的可用性。架构更改期间的停机或表锁定(例如添加索引)是不可接受的。

    架构更改在多个F1服务器上异步应用。通过使用只支持当前和下一个模式版本的模式租赁机制防止异常;通过将模式更改细分为多个阶段,其中连续的更改对是相互兼容的,ad不会导致异常。模式更改算法的全部细节将在另一篇论文中提供。

    • 快照、悲观和乐观事务支持,乐观事务是默认模式。
    • 灵活的锁粒度允许用户指定覆盖列子集的其他锁。
    • F1用户经常在父表中使用锁列,以避免为特定谓词插入幻象,或使其他业务逻辑约束更易于实施。
    • 完全集成的变更历史机制(听起来像基于SQL的连续查询(CQ)支持这些变更)。

    许多数据库用户构建了记录更改的机制,可以从应用程序代码中记录更改,也可以使用诸如触发器之类的数据库功能。在AdWords在F1之前使用的MySQL系统中,我们的Java应用程序库将变更历史记录添加到所有事务中。这很好,但效率很低,从来没有100%可靠。某些更改类无法获取历史记录,包括从Python脚本编写的更改和手动SQL数据更改。在F1中,更改历史记录是数据库级别的一流功能。

    NoSQL键/值存储接口

    • 一个成熟的SQL接口,用于OLTP和OLAP查询。
    • 对ORM也有一个有趣的见解。谷歌发现,一个分布式商店,即使它完全支持SQL接口,也需要另一种ORM方法:
      1. 使用分布式数据存储的本质要求我们重新思考客户机应用程序与数据库交互的方式。我们的许多客户机应用程序都是使用基于MySQL的ORM层编写的,不能很好地与F1配合使用。使用这个库编写的代码展示了几种常见的ORM反模式……对于F1,我们用一个新的、精简的API替换了这个ORM层,它强制避免了这些反模式。新的ORM层不使用任何连接,也不隐式遍历记录之间的任何关系。所有对象加载都是显式的,ORM层公开了促进并行和异步读取访问的api。

    这篇论文对F1如何处理查询进行了很好的讨论,对此我请您参考原文。
    不过,所有对开发人员友好的功能最终都必须付出代价,而在F1的设计中所做的权衡中,这最明显地表现为CPU使用率的增加。
    F1中的资源成本通常更高,在F1中,查询通常比类似的MySQL查询使用更多数量级的CPU。MySQL将未压缩的数据存储在本地磁盘上,并且通常被磁盘而不是CPU所限制,即使使用闪存磁盘也是如此。F1查询从磁盘上压缩的数据开始,经过若干层,经过解压缩、处理、重新压缩和通过网络发送,所有这些都有很大的成本。提高CPU效率是未来工作的一个领域。