去年12月1日 AWS 发布 Amazon S3 支持写后读数据的强一致性,作者随后发表了《当对象存储“湖”有了强一致性》探讨了第一个云服务“互联网存储 Amazon S3”强一致性的具体含义。作为一个架构师,非常好奇,AWS 团队如何在如此超大规模 S3 用户和数据量的前提下,改造分布式的 S3 系统为所有用户实现免费的数据强一致性特性,而且 S3 的性能几乎没有受到影响?终于等到新鲜出炉的 Werner 博士在自己 All Things Distributed 站点上的分享。
我们构建 S3 是因为我们知道客户希望为电子商务网站等应用程序存储备份、视频和图像。我们当时设计最高优先级是安全性、弹性、可靠性、持久性、性能和成本,因为这是客户告诉我们对于这样的应用程序而言这些最重要的,今天仍然如此。但是,多年来,S3 也已成为大规模数据湖上用于分析和机器学习的存储空间。这些数据湖不仅仅为电子商务网站存储图像,而且为卫星图像分析、疫苗研究以及自动驾驶卡车和汽车研发等应用提供数据。
要为如此广泛的用途提供存储能力,需要不断提升服务的能力;我认为这就是 S3 最有趣的事情之一,这从根本上改变了客户使用存储的方式。在 S3 之前,客户因为数据中心购买的昂贵的本地存储系统的容量和功能而绑定 3到5 年,如果您想获得更多容量或新功能,则需要购买新的本地存储设备,然后需要在存储阵列之间迁移数据。借助 S3 按需付费模式以及针对新功能的不断创新,S3 改变了游戏规则,可以在不对应用程序进行重大更改的情况下提升数据使用效率。
- 1 - 一致性模型
一致性模型是分布式系统中的一个概念,它定义了数据更新的顺序和可见性规则,它们本身可以有多方面取舍,使架构师能够针对最重要的组件优化分布式系统。
对于 S3,我们将缓存技术构建到元数据子系统中,以便于提升高可用性,但该设计决策的潜在含义之一是,在极少数情况下,我们会在写入场景中呈现最终一致性。换句话说,系统几乎始终可用,但有时 API 调用会返回尚未在系统中所有节点中完全传播的对象的旧版本。2006 年为站点存储图片或备份副本时,最终一致性是合适的。
15 年后到今天,S3 拥有超过 100 万亿个对象,每秒处理数千万次请求。多年来,客户发现了许多 S3 的新使用场景:例如,成千上万的客户使用 S3 进行数据湖,他们在那里执行分析,为其业务创造了新的见解(和竞争优势),这是几年前不可能达到的规模;客户还使用 S3 存储 PB 级的数据来训练机器学习模型;这些与存储的交互绝大多数是通过应用程序代码完成的,这些数据处理应用通常需要强一致性 —— 对象需要并行在所有节点上保持相同 —— 因此客户编写自己的应用程序代码,以便跟踪 S3 使用情况的一致性;客户喜欢 S3 的弹性、成本、性能、运维配置文件和编程模型的简单性,因此,当他们的应用需要在存储中保障强一致性成为至关重要的前提时,他们自己编写自定义的应用程序代码以利用 S3 的优势。例如,Netflix 开源 s3mper,它使用 Amazon DynamoDB 作为一致的存储来识别 S3 将提供不一致响应的罕见情况;Cloudera 和 Apache Hadoop 社区在 S3Guard 上合作,同样为应用程序提供了一个单独的视图,以避免 S3数据的不一致。
尽管客户能够使用额外的元数据跟踪系统为其应用程序提供 S3 强一致性,但必须构建和管理额外的基础设施。请记住,我们在 AWS 的路线图中有 90% 的创新直接来自客户,客户询问我们是否可以更改 S3 以避免他们需要运行额外的基础设施。我们回顾了 S3 构建之初的核心设计原则,2006 年的情况确实如此,今天仍然是我们如何构建 S3 功能的基石。所以我们开始考虑如何更改 S3 的一致性模型,我们知道这会很难,一致性模型被编码到 S3 的核心基础架构中。
我们思考强一致性的实现,就像我们考虑所有决策的方式一样:从客户开始。我们考虑了需要在成本、哪些对象需要具有一致性或性能方面进行权衡的方法;我们不想做任何妥协,因此,我们一直在努力实现更高的标准:我们希望在不增加成本的情况下实现强一致性,应用于每个新的和现有的对象,而且没有性能或可用性的损失。
其他厂商为了实现强一致性做出了某些妥协,例如将强一致性作为某个存储桶或账户的特定设置而不是所有对象存储的默认选择,又或一致性的实现依赖于跨区域设计,从而受制于某个服务的区域级可用性保障或其它限制。如果我们想改变这一基本的一致性概念,坚持我们的 S3 设计原则,我们需要使强一致性成为每个请求的默认且免费设置,而不会影响性能,并遵守我们的可靠性模型。这使得本身就比较困难的工程问题变得更加困难,尤其是在 S3 的超大规模下。
- 2 - S3 元数据子系统
每个对象的元数据存储在独立的 S3 子系统中,该子系统位于 GET、PUT 和 DELETE 请求的数据路径上,并主要负责处理 LIST 和 HEAD 请求。该子系统的核心是存储元数据的持久化层;我们的持久层使用旨在具有高弹性的缓存技术,即使支持缓存的基础设施受到损害,S3 请求仍应成功,这意味着,在极少数情况下,写入操作可能会流经缓存基础架构的一部分,而读取最终会查询另一部分,这是 S3 最终一致性的主要原因。
提供强一致性的早期考量之一是绕过我们的缓存基础架构,直接向持久层发送请求,但是,这不符合我们的高标准要求,因为这样做的后果会损失性能;我们需要保留缓存设计,为了在不同存储单元之间保持数据值正确同步,我们实现了缓存一致性协议;这就是我们在这里需要的:元数据缓存子系统的缓存一致性协议,允许所有请求的高一致性。
- 3 - 缓存一致性
我们强一致性场景要求我们在超大规模的 S3 上,使元数据缓存具有高度一致性,这是一项艰巨的任务,我们希望在尊重我们元数据系统的规模、弹性和运维方面学到的经验教训的同时进行这种改变。
我们在元数据持久层中引入了新的复制逻辑,该逻辑作为一个新的功能模块,实现至少一次事件通知系统和复制时间控制特性;这种新的复制逻辑允许我们对 S3 中每个对象的 “操作顺序” 进行推理,这是我们缓存一致性协议的核心部分。
我们在 S3 元数据子系统中引入了一个新组件,以了解缓存对象元数据的视图是否已过时;此组件充当写入的“见证人”,每次对象更改时都会发出通知;这个新组件在读取操作期间起到读取屏障的作用,允许缓存了解其对象视图是否过时;如果缓存的值没有过时,则可以直接返回;如果缓存值已过时,则可以使缓存值失效并从持久性层读取。
这种新设计在两个方面给我们带来了挑战。首先,缓存一致性协议本身必须是正确的;强一致性必须始终保持强大,毫无意外发生;其次,客户喜欢 S3 的高可用性,因此我们对新组件的设计必须确保它不会降低 S3 的高可用性。
- 4 - 高可用性
“见证人 Witnesses ”在分布式系统中很受欢迎,因为他们通常只需要在内存中跟踪一点状态,而无需落盘;这使他们能够以非常低的延迟实现极高的请求处理速率;这就是我们在这里所采用的,随着 S3 的持续增长,我们可以继续向外扩展这个队列。
除了极高的吞吐量之外,我们还利用我们 15年运营大规模系统经验,构建此系统以满足 S3 的高可用性要求;正如我一直表达的一个观点,考虑每个节点都会失败的可能性;因此,我们基于个别主机/服务器会出现故障的假设进行系统设计;我们构建了自动化机制,可以快速响应负载过高和单个服务器故障;由于一致性“见证人”追踪最小状态并且只跟踪内存中的状态,因此我们能够快速更换它们,而无需等待长时间的状态转换;
- 5 - 正确性验证
正确实施强一致性非常重要,这样就不会出现破坏一致性的极端情况。S3 是一个大规模的分布式系统,正常情况下,这种新的缓存一致性协议不仅需要正确,而且在所有情况下都需要正确。当对同一对象的并发写入正在进行时,它必须是正确的,否则,我们可能会看到新旧值之间 “闪烁”;当单个对象在启用版本控制并具有深度版本堆栈的同时,在 GET、LIST、PUT 和 DELETE 上看到非常高的并发时,它需要正确;操作和中间状态存在无数次交错,按照我们的规模,即使某些事情只在十亿个请求中发生一次,也意味着它在 S3 中每天发生多次。
在任何生产系统中,单元测试和集成测试等常见测试技术都是有价值的必要工具。但是,当你需要构建一个具有如此高标准的系统以保证正确性时,这还不够;我们想要一个 “可证明正确” 的系统,而不仅仅是 “可能正确” 的系统;因此,为了实现强大的一致性,我们使用了各种技术来确保我们构建的东西是正确的,并且随着系统的发展而继续正确;我们采用了集成测试、建议的缓存一致性算法的演绎性证明、模型检查来形式化我们的一致性设计并证明其正确性,我们扩展了模型检查以检查实际可运行的代码。
这些验证技术有很多工作,事实上,它们比实现强一致性本身的工作还要多。但是,我们在 S3 强一致性的设计和实施中加以严格考虑,因为这正是我们的客户所需要的。
- 6 - 总结
我们根据 2006 年推出该服务时提出的设计原则构建 S3,每次我们审查 S3 中新功能或微服务的设计时,我们都会回到这些原则,通常,提供强一致性,而不会给客户带来额外费用,而且高性能是一个巨大的挑战;S3 利用超过 15 年在数百万客户中大规模运营云存储的经验来创新其他任何地方都无法使用的功能,我们利用这种经验在 S3 的客户享受高可用性下增加了强一致性;而且,通过利用各种测试和验证技术,我们能够通过一个高度一致的系统提供客户所需的正确性,最重要的是,我们能够以对客户透明的方式做到这一点,并坚持 S3 的核心价值观。
附录——发布于 2006 年的 Amazon S3 服务 Day 1 的设计原则:
在科技领域,15 年是很长的时间。早在 S3 于 2006 年 3 月 14 日推出时(也被称为 “Pi Day”),iPhone 并不存在,也没有推文或点赞,Facebook 仍然只被少数学院和大学使用,而且你无法在线使用 App 欢呼或订购午餐。
当时,亚马逊的规模约为今天的 2%,增长速度超过传统 IT 系统的支撑能力。我们必须重新思考之前关于构建可扩展系统的所有知识。存储是我们最大的痛点之一,我们使用的传统 IT 系统不符合 Amazon.com 在线零售业务的需要。
2005 年,当我们仔细查看 Amazon.com 站点的存储时,我们意识到大多数数据需要对象(或键值)存储。我们有 Amazon.com 上销售商品的图片、视频文件等,我们需要的是低成本和高可靠性,而这样的存储解决方案当时并不存在。当时,数据存储通常存在于块存储和文件存储中。对象存储平台已经存在,但它们无法扩展以适应我们的发展的需要。正如我们在 S3 最初的新闻稿所述,我们需要满足以下设计标准的存储服务:
- 可扩展:Amazon S3 可以在存储大小、请求速率和用户数方面进行扩展,以支持无限数量的大规模 Web应用程序;它的扩展性作为一项优势,向系统添加节点会增加而不是减少系统的可用性、速度、吞吐量、容量和稳健性。
- 可靠:持久化存储数据,可用性为 99.99%;不能有任何单点故障,系统必须在不停机的情况下容忍或修复所有故障。
- 快速:Amazon S3 必须足够快才能支持高性能应用程序;服务器端延迟与互联网延迟相比必须微不足道,只需将节点添加到系统中,就可以修复任何性能瓶颈;
- 廉价:Amazon S3 由廉价的商业标准硬件组件构建,因此,频繁的节点故障是常态,不得影响整个系统;它必须与硬件无关,这样,随着亚马逊继续降低基础设施成本,就可以节省成本。
- 简单:构建高度可扩展、可靠、快速且经济实惠的存储非常困难;而对于任何应用程序,可以随时随地轻松访问更加困难。Amazon S3 必须同时满足这两点;
扩展阅读:
- “见证人 Witnesses ”*:Voting with Witnesses: A Consistency Scheme for Replicated Files
- Amazon S3 2006年新闻稿:http://u8s.net/m9v08