AWS CTO对过去十年的经验总结 – 十条军规
AWS(Amazon Web Service) 开始于 2006 年 3 月 14 日 Amazon S3 的发布,距今已有十年时间。回首过去十年,我们在构建和运营 AWS 云计算服务中积累了大量的经验教训——这些服务不仅需要确保安全性、可用性和可扩展性,同时还要以尽可能低廉的成本提供可预测的性能。考虑到 AWS 是世界范围内构建和运营此类服务的开拓者,这些经验教训对我们的业务来说至关重要。正如我们多次重申的,“经验不存在压缩算法”。考虑到 AWS拥有每月超过一百万的活跃用户,而这些用户也许会为数以亿计的自家客户提供服务。因此,积累上述经验教训的机会在 AWS 比比皆是, 在这些经验教训中,我挑选了一些分享给大家,希望对各位也能有所帮助。
1.构建可持续演进的系统
从做 AWS 的第一天开始,我们就清楚地认识到,我们在做的这套软件不是一劳永逸的。现在可以用的软件,一年之后很可能将不再适用。我们的预期是,随着(用户)数量级的增加一或两次,我们都需要重新检视和适当修改我们已有的架构,以便解决扩展性的问题。
但是我们无法采取过去常用的通过检修停机进行系统升级的方式来实现上述目标,因为世界各地诸多业务都依赖着我们平台所提供的7 x 24 小时的可用性。因此,我们需要构建一个在引入新的软件构件时不会引起服务瘫痪的架构。Amazon 杰出的工程师 Marvin Theimer 有一次开玩笑说,Amazon S3 这项服务的持续演进用开飞机来形容最为贴切。我们最开始开的是一架单引擎的赛斯纳,一段时间后升级成一架波音 737,之后又换成了一支波音 747 小队,而现在更像是由空中巨无霸空客 A380 组成的一支大型机队。自始至终,我们一边通过空中加油确保飞机的正常飞行,一边在万米高空上将 AWS 的用户从一架旧飞机挪到另一架新的上面去。同时,AWS 的用户对此毫不知情。
2. 预料到不可预料的情况
故障是注定的;随着时间的流逝,一切终将归于失败:从路由器到硬盘,从操作系统到存储单元损坏的TCP数据包,从瞬时误差到永久失效,无论你用的是最高质量的硬件还是最低成本的组件,这都是理所当然的。
在服务规模变得很大之后,这个问题愈加地凸显:举例来说,当Amazon S3 服务处理万亿级存储交易时,即使误差概率极小的事件也将成为现实。在设计和构建阶段,这些故障场景中的一部分事先会被考虑到,但更多的则是未知数。
因此,我们需要构建的是将故障视为自然发生的系统,即使我们并不知道故障是什么。这个系统应该要做到,即使在“后院已经着火”的情况下依然可以继续运行。重要的是在不需要引起整个系统宕机的情况下就能管理好受影响的局部组件。对此,我们已经发展出一套控制故障发生影响范围的基本技能,以期系统的总体健康状态得以维持。
3. 提供基元而非框架
很快我们开始发现,用户大都喜欢在 AWS 提供的服务上持续构建和演进自己的业务系统。在摆脱了传统 IT 硬件和数据中心的束缚之后,他们开始以一种全新、有趣的、之前从未出现过的使用模式开发自己的系统。也正是因为如此,为了满足用户多样的需求,我们的架构需要保持高度的灵活性。
关于这一点,最重要的机制之一就是,我们提供给用户的是一系列基元和工具,用户可以选择他们喜欢的方式来使用AWS云服务,而不是由我们提供一个大而全的统一的框架。这个机制给我们的用户带来了巨大的成功,甚至 AWS 自身后续的一些服务也用上了这套机制,就像我们的普通用户一样。
同样重要的一点是,我们很难在用户还没开始使用一个服务之前,就准确预知到对用户而言该服务需要优先考虑的问题。这也是为什么所有的新服务最初都会以最小的功能集发布,然后借助用户的反馈,再对该服务进行后续的扩展。
4. 自动化是关键
开发一个需要持续维护的软件服务和开发一个最终交付给客户的软件有着巨大的差异,管理一个像 AWS 这种规模的系统,需要一种完全不同的观念,才能确保满足用户对可用性、性能以及可扩展性的要求。
实现这个目标的一个主要的机制,就是避免容易产生误差的手工操作,尽可能地将管理工作自动化。为此,我们需要构建一套可以控制主要功能的管理 API。在这方面,我们同时也对自己的用户给予帮助。通过将应用分解成一个个独立的模块,每个模块都有自己的管理 API,你可以很方便地定义自动化规则来进行大规模的维护。判断自动化做的是不是到位,可以思考一下你是不是还需要使用SSH登陆到某台服务器进行运维操作?如果答案是 yes,说明你的自动化做得还不够好。
5. API 定义要严谨,因为一旦上线就无法更改
我们在 Amazon 零售项目中已经接受过类似的教训,但对于 AWS 这种以 API 为中心的服务,这个原则变得更加重要。一旦用户开始用我们的 API 开发他们的应用和系统,我们就不可能再对这些 API 进行变更了。因为 API 的任何改动都会影响到用户已有的项目。因此我们充分意识到,在 API 给到用户之前,我们只有一次将 API 做对的机会。
6. 监控你的资源使用情况
当你为一项服务确定计费模式的时候,请务必确保你有一份关于该服务的资源成本和运营的数据。对于边际成本很低的业务尤其如此。作为服务提供 商,AWS 需要对服务成本保持足够的敏感,以便我们能清楚地认识到我们是否承担得起某项服务,同时也能够定位到一些可以通过提高运营效率而进一步降低成本的地方,并借此降低服务价格,最终惠及用户。
举一个例子,早期的时候,我们对于 Amazon S3 服务所用到的资源成本并不是很清晰。我们当时假定,存储和带宽应该是我们首要考虑的收费点;后来运行了一段时间之后,我们才意识到,请求数量跟存储与带宽同 等重要。如果某个用户有大量的小文件要存储,这种情况下,即使是百万量级的请求,都不会占用太多的存储和带宽资源。最终我们做了调整,将请求数量也纳入了计费模型,以便 AWS 在收支上可以保证这项服务的可持续性。
7. 从头开始建立安全机制
保护你的用户,这一点的优先级永远都应该排在第一位,在 AWS 也不例外。不光要从运营的角度,还要从工具和机制的角度保证这一点。对此,我们也将继续保持最高的支持与投入。我们很快就学到的一个经验就是,为了实现安 全的服务,我们需要在服务设计的最初阶段就抱有这种安全意识。安全团队的任务不是在一项服务实现完了之后才开始安全检查,相反地,安全团队的工作应该和开 发团队一道,贯穿于整个项目的生命周期,以确保项目的安全性。总之,涉及到安全的问题,没有任何妥协的余地。
8. 数据加密是头等大事
数据加密,是保证用户数据安全的重要机制。十年前,数据加密相关的工具和服务还不够完善,直到 AWS 刚开始运营的最初几年,我们才逐步积累了很多关于在服务中集成数据加密的最佳实践。
Amazon S3 最初提供的,是服务器端的加密机制。当我们在数据中心移除带有用户数据的磁盘的时候,这些数据就无法被访问到了。但是后续上线的诸如 Amazon CloudHSM 和 Amazon Key 管理服务,均向用户提供了自定义加密密钥的机制,这样一来,AWS 就不需要替用户维护这些加密密钥了。
现在,AWS 所有的新服务,在原型设计阶段就会考虑到对数据加密的支持。比如,在 Amazon Redshift 服务中,每一个数据块都通过一个随机的密钥进行加密,而这些随机密钥则由一个主密钥进行加密存储。用户可以自定义这个主密钥,这样也就保证了只有用户本人才能访问这些机密数据或敏感信息。
数据加密在我们的业务中的优先级一直非常高。我们也会持续改进,让数据加密机制用起来更简单,最终,让用户能更好地保护自己的数据安全。
9. 网络的重要性
AWS的服务支撑了各种各样的负载场景。从高并发处理到视频转码,从高性能并行计算到海量的网络请求。这些不同的负载场景,对网络的要求也各不相同。
关于数据中心的设计和运营,AWS 开发了一套独特的机制,这套机制提供了灵活的网络基础设施,以便满足任何用户的不同负载场景的需求。在这个过程中,我们也认识到,为了让用户达成自身的目 标,我们必须开发自己的网络解决方案。这样也能满足我们自身的一些定制化的需求,比如在保证高安全性的同时,通过网络来隔离用户的能力。
AWS 自主开发的这套软硬件解决方案,也能给用户带来进一步的性能提升。关于这一点,有一个成功的例子,那就是虚拟机之间的网络通信。由于网络通信是一个共享的资源,在使用 AWS 自己定制的解决方案之前,用户时常会遇到网路拥堵的问题。最终,AWS 通过开发支持单个根 IO 虚拟化技术的 NIC,实现了给每个虚拟机虚拟出自己的 NIC 的解决方案。这一改动成倍地降低了网络延迟,同时提升了高达十倍的网络性能。
10. 不设限,保持平台的中立与开放
随着时间的推移,AWS 团队提供了越来越多的服务和功能,这也给我们的用户创造了一个广阔的开发平台。但是 AWS 远不止我们团队开发的这些功能与服务,一些合作伙伴基于 AWS 提供的服务进一步扩大和丰富了整个系统的生态。比如,我们的合作伙伴 Stripe 提供的支付服务得以让 Twilio 在 AWS 上支持电话业务。
很多用户基于 AWS 本身的服务,开发出自己的产品,用于解决特定的垂直领域的问题。比如,飞利浦开发了用于健康数据管理的 Healthsuite 数字平台;Ohpen 则基于 AWS 开发出自己的零售银行平台;Eagle Genomics 开发了自己的计算平台用于基因处理等等,这样的例子不胜枚举。AWS 并不会限制我们的合作伙伴,规定他们什么可以做什么不可以做。“不设限”的原则释放了创新的动力,为意想不到的创新敞开了大门。