使用可用区实现静态稳定性 - 设计高可用系统

1 分钟阅读
内容级别:高级
0

本文旨在向读者介绍AWS中使用的静态稳定性模式,以设计高可用系统。文中详细描述了Amazon如何通过可用区的独立性和静态稳定性原则,确保其服务在依赖关系受损的情况下仍能保持高可用性。本文不仅介绍了这些概念的理论基础,还通过具体的示例展示了Amazon EC2等服务如何应用这些原则来实现高可用性。这些内容对于希望在AWS上构建高可用性应用的开发者和架构师具有重要参考价值。

AWS 静态稳定性模式:设计高可用系统

在Amazon,我们构建的服务必须满足极高的可用性目标。这意味着我们需要仔细考虑系统所依赖的各项依赖关系。我们设计系统时,确保即使这些依赖关系受损,系统仍能保持弹性。在本文中,我们将定义一种称为静态稳定性的模式,以实现这种级别的弹性。我们将向您展示如何将这一概念应用于可用区(Availability Zones),这是AWS关键的基础设施构建模块,因此是我们所有服务构建的基石依赖。

在静态稳定设计中,即使依赖关系受损,整个系统仍能继续工作。也许系统不会看到依赖关系应传递的新信息(例如新事物、删除的事物或修改的事物),但是在依赖关系受损之前它所做的一切将继续正常运作。我们将描述我们如何构建Amazon Elastic Compute Cloud(EC2)使其具有静态稳定性。接着,我们将提供两个静态稳定的示例架构,这些架构在构建基于可用区的高可用区域系统方面非常有用。

最后,我们将深入探讨Amazon EC2的一些设计理念,包括如何在软件层面提供可用区独立性。此外,我们还将讨论选择这种架构时的一些权衡取舍。

可用区的角色

可用区是AWS区域内逻辑隔离的部分:每个AWS区域有多个可用区,这些可用区设计为独立运行。可用区在物理上分隔了一段有意义的距离,以防止潜在问题(如雷击、龙卷风和地震)带来的关联影响。它们不共享电力或其他基础设施,但它们通过快速、加密的光纤网络相互连接,使应用程序能够快速无中断地进行故障转移。换句话说,可用区为我们的基础设施隔离提供了一个抽象层。需要可用区的服务允许调用者告诉AWS在区域内的物理位置部署基础设施,以便从这种独立性中受益。在Amazon,我们构建了利用这种区域独立性来实现自身高可用性目标的区域AWS服务。Amazon DynamoDB、Amazon Simple Queue Service(SQS)和Amazon Simple Storage Service(S3)就是这样的区域服务的示例。

当与在Amazon Virtual Private Cloud(VPC)内部署云基础设施的AWS服务交互时,许多服务要求调用者不仅指定区域,还指定可用区。可用区通常隐含在必需的子网参数中,例如在启动EC2实例、配置Amazon Relational Database Service(RDS)数据库或创建Amazon ElastiCache集群时。尽管在一个可用区中通常有多个子网,但单个子网完全位于单个可用区内,因此通过提供子网参数,调用者也隐含地提供了要使用的可用区。

静态稳定性

在基于可用区构建系统时,我们学到的一课是要在故障发生前做好准备。一种不太有效的方法可能是在多个可用区中部署,期望如果某个可用区发生故障,服务将在其他可用区(可能使用AWS Auto Scaling)中扩展并恢复到完全健康状态。这种方法不太有效,因为它依赖于在故障发生时做出反应,而不是在故障发生前做好准备。换句话说,它缺乏静态稳定性。相反,更有效的静态稳定服务会过度配置其基础设施,以至于即使某个可用区受损,也能继续正常运行,而无需启动任何新的EC2实例。

为了更好地说明静态稳定性的特性,让我们来看一下Amazon EC2,它本身就是根据这些原则设计的。

Amazon EC2服务由控制平面和数据平面组成。“控制平面”和“数据平面”是网络中的术语,但我们在AWS中广泛使用它们。控制平面是涉及对系统进行更改的机制——添加资源、删除资源、修改资源——并将这些更改传播到需要生效的地方。相反,数据平面是这些资源的日常业务,即使它们正常运行所需的一切。

在Amazon EC2中,控制平面包含EC2启动新实例时发生的所有事情。控制平面的逻辑通过执行许多任务来汇总启动新EC2实例所需的一切。以下是几个示例:

  • 在遵守放置组和VPC租赁要求的情况下,为计算选择物理服务器。
  • 从VPC子网分配网络接口。
  • 准备Amazon Elastic Block Store(EBS)卷。
  • 生成AWS Identity and Access Management(IAM)角色凭证。
  • 安装安全组规则。
  • 将结果存储在各种下游服务的数据存储中。
  • 将所需配置传播到VPC中的服务器和网络边缘。

相反,Amazon EC2数据平面保持现有EC2实例正常运行,执行诸如以下任务:

  • 根据VPC的路由表路由数据包。
  • 从Amazon EBS卷读取和写入数据。
  • 诸如此类。

通常情况下,数据平面比控制平面简单得多。因此,Amazon EC2数据平面的设计目标是比Amazon EC2控制平面具有更高的可用性。

重要的是,Amazon EC2数据平面经过精心设计,即使在控制平面可用性事件(例如启动EC2实例的能力受损)中也能保持静态稳定性。例如,为避免网络连接中断,Amazon EC2数据平面设计为物理机器上运行的EC2实例可以本地访问所有必要的信息,以便将数据包路由到其VPC内部和外部的各个点。控制平面受损意味着在事件期间物理服务器可能看不到更新(例如添加到VPC的新EC2实例或新的安全组规则)。然而,在事件发生前它能够发送和接收的流量将继续正常工作。

控制平面、数据平面和静态稳定性的概念不仅适用于Amazon EC2。能够将系统分解为控制平面和数据平面是设计高可用服务的一个有用概念工具,原因如下:

  • 数据平面的可用性对服务客户的成功通常比控制平面更为关键。例如,对于大多数AWS客户来说,EC2实例运行后的持续可用性和正确运行比启动新EC2实例的能力更为重要。
  • 数据平面的操作量通常比控制平面高(通常高出几个数量级)。因此,最好将它们分开,以便每个都可以根据其相关的扩展维度进行扩展。
  • 多年来,我们发现控制平面比数据平面有更多的移动部件,因此仅因这个原因就更有可能受到影响。

综合考虑这些因素,我们的最佳实践是沿着控制平面和数据平面的边界分离系统。

静态稳定性模式

在本节中,我们将介绍两个我们在AWS中用来设计高可用系统的静态稳定性高层模式。每个模式适用于自己的特定情况,但都利用了可用区的抽象。

可用区上的主动-主动示例:负载均衡服务

多个AWS服务内部由水平可扩展的无状态EC2实例或Amazon Elastic Container Service(ECS)容器组成。我们在跨三个或更多可用区的Auto Scaling组中运行这些服务。此外,这些服务会过度配置容量,因此,即使整个可用区受损,剩余可用区中的服务器也可以承担负载。例如,当我们使用三个可用区时,我们过度配置50%的容量。换句话说,我们过度配置,使得每个可用区仅在66%的负载测试水平上运行。

最常见的示例是负载均衡的HTTPS服务。下图显示了一个提供HTTPS服务的面向公众的应用程序负载均衡器。负载均衡器的目标是跨eu-west-1区域三个可用区的Auto Scaling组。这是使用可用区的主动-主动高可用性的示例。

Enter image description here

在可用区受损的情况下,上述架构无需采取任何行动。受损可用区中的EC2实例将开始失败健康检查,应用程序负载均衡器将把流量从它们转移开。实际上,Elastic Load Balancing服务是根据这一原则设计的。它预置了足够的负载均衡容量,以承受可用区受损而无需扩展。

即使没有负载均衡器或HTTPS服务,我们也会使用这种模式。例如,处理来自Amazon Simple Queue Service(SQS)队列消息的EC2实例群也可以遵循此模式。这些实例部署在跨多个可用区的Auto Scaling组中,适当地过度配置。在可用区受损的情况下,服务无需采取任何行动。受损实例停止工作,其他实例接管工作。

可用区上的主动-备用示例:关系数据库

我们构建的一些服务是有状态的,需要单个主节点或领导节点来协调工作。例如,使用关系数据库的服务,如使用MySQL或Postgres数据库引擎的Amazon RDS。此类关系数据库的典型高可用性设置有一个主实例,它是所有写操作必须去的地方,还有一个备用候选实例。我们还可能有额外的只读副本,这些副本未显示在下图中。使用此类有状态基础设施时,将在主节点所在的可用区之外的不同可用区中保持一个备用候选实例。

下图显示了一个Amazon RDS数据库。当我们使用Amazon RDS配置数据库时,它需要一个子网组。子网组是跨多个可用区的一组子网,数据库实例将在其中进行配置。Amazon RDS将备用候选实例放置在与主节点不同的可用区。这是使用可用区的主动-备用高可用性的示例。

Enter image description here

与无状态的主动-主动示例一样,当主节点所在的可用区受损时,有状态服务无需对基础设施进行任何操作。对于使用Amazon RDS的服务,RDS将管理故障转移并重新指向DNS名称到工作可用区的新主实例。这一模式也适用于其他主动-备用设置,即使它们不使用关系数据库。特别是,我们将其应用于具有领导节点的集群架构系统。我们跨可用区部署这些集群,并从备用候选中选举新领导节点,而不是“及时”启动替换节点。

这两种模式的共同点是它们在实际受损之前已预置了所需的容量。在任何一种情况下,服务在响应可用区受损时都不会采取任何有意的控制平面依赖,例如配置新基础设施或进行修改。

Amazon EC2中的静态稳定性

本文最后一节将更深入地探讨Amazon EC2中的一些设计理念,以帮助我们构建不仅需要自身高可用性,还需要为其他应用提供高可用性基础设施的服务。作为AWS底层基础设施的提供者,Amazon EC2是应用程序可以用来实现高可用性的基础设施。其他系统有时也希望采用这种策略。

我们在Amazon EC2中的部署实践遵循可用区独立性原则。在Amazon EC2中,软件部署到托管EC2实例的物理服务器、边缘设备、DNS解析器、EC2实例启动路径中的控制平面组件,以及EC2实例依赖的许多其他组件。这些部署遵循区域部署日历。这意味着同一区域中的两个可用区将在不同的日子收到给定的部署。在AWS中,我们采用分阶段的部署方式。例如,无论部署到何种服务,我们都遵循最佳实践,首先部署一个盒子,然后是1/N的服务器,等等。然而,在Amazon EC2等服务的具体情况下,我们的部署更进一步,并故意对准可用区边界。这样,一次部署的问题影响一个可用区时,可以回滚和修复,而不会影响其他可用区,它们将继续正常运行。

在Amazon EC2中,设计所有数据包流量保持在可用区内而不是跨越边界,是应用可用区独立性原则的另一种方式。这一点值得详细探讨。它是我们在构建区域性、高可用性系统时,与提供可用区独立性基础设施给其他人使用的区别的一个有趣例子。

下图说明了一个依赖于另一个内部服务的高可用外部服务(橙色)。一种简单的设计是将这两个服务都视为独立EC2可用区的消费者。橙色和绿色服务都由应用程序负载均衡器前置,每个服务都有一支跨三个可用区的后端主机队列。这是一个高可用区域服务调用另一个高可用区域服务的简单设计,对我们构建的许多服务来说,这是一种不错的设计。

Enter image description here

假设绿色服务是一个基础服务。也就是说,假设它不仅旨在高可用性,而且还旨在作为提供可用区独立性的构建块。在这种情况下,我们可能会将其设计为三个区域本地服务实例,我们遵循可用区感知的部署实践。下图说明了一个高可用区域服务调用高可用区本地服务的设计。

Enter image description here

我们将构建块服务设计为可用区独立性的原因归结为简单的算术。假设一个可用区受损。对于黑白故障,应用程序负载均衡器将自动避开受影响的节点。然而,并非所有故障都是如此明显。可能存在灰色故障,例如软件中的错误,负载均衡器无法在其健康检查中看到并干净地处理。

在前面的示例中,一个高可用区域服务调用另一个高可用区域服务,如果请求通过系统发送,那么在一些简化假设下,请求避开受损可用区的机会是2/3 * 2/3 = 4/9。也就是说,请求避开事件的几率不到一半。相反,如果我们将绿色服务构建为区域本地服务,那么橙色服务中的主机可以调用同一可用区的绿色端点。使用这种架构,避开受损可用区的机会是2/3。如果N个服务是调用路径的一部分,这些数字则推广为区域服务的(2/3)^N,而区域服务保持为2/3。

正因为如此,我们将Amazon EC2 NAT网关构建为区域本地服务。NAT网关是Amazon EC2的一项功能,允许从私有子网进行出站互联网流量,并显示为区域性的,而不是区域性的VPC网关,客户可以分别在每个可用区实例化,如下图所示。NAT网关位于VPC的互联网连接路径中,因此它是任何EC2实例数据平面的一部分。如果某个可用区的连接受损,我们希望将该受损局限于该可用区,而不是传播到其他区域。最终,我们希望构建类似于本文早前提到的架构(即通过预配置跨三个可用区的容量,确保任何两个可用区能够承担全部负载)的客户知道,其他可用区将完全不受受损可用区中的任何事情的影响。我们唯一的办法是确保所有基础组件——如NAT网关——确实保持在可用区内。

Enter image description here

这一选择带来了额外的复杂性。对于我们在Amazon EC2中的复杂性,额外的复杂性体现在管理区域而非区域的服务环境中。对于NAT网关的客户,额外的复杂性体现在拥有多个NAT网关和路由表的情况下,以便在VPC的不同可用区中使用。额外的复杂性是适当的,因为NAT网关本身是基础服务,是Amazon EC2数据平面的一部分,旨在提供区域可用性保证。

在构建可用区独立性的服务时,我们还考虑数据持久性。尽管前面描述的每个区域架构显示整个堆栈包含在单个可用区内,但我们跨多个可用区复制任何硬状态以进行灾难恢复。例如,我们通常将定期数据库备份存储在Amazon S3中,并在可用区边界维护数据存储的只读副本。这些副本不是主可用区正常运行所必需的。相反,它们确保我们在多个位置存储客户或业务关键数据。

在设计将在AWS中运行的面向服务的架构时,我们学会了使用这两种模式之一,或两者的结合:

  • 更简单的模式:区域调用区域。这通常是面向外部服务的最佳选择,也适用于大多数内部服务。例如,在AWS中构建更高级别的应用程序服务时,如Amazon API Gateway和AWS无服务器技术,我们使用这种模式即使在可用区受损的情况下也能提供高可用性。
  • 更复杂的模式:区域调用区域或区域调用区域。在Amazon EC2内构建内部或某些情况下的外部数据平面组件时(例如,位于关键数据路径中的网络设备或其他基础设施),我们遵循可用区独立性模式,使用隔离在可用区中的实例,以便网络流量保持在其同一可用区内。这种模式不仅有助于将故障隔离到一个可用区,还具有有利的AWS网络流量成本特性。

结论

在本文中,我们讨论了一些在AWS中成功依赖可用区的简单策略。我们了解到静态稳定性的关键是提前预见故障。无论系统是运行在主动-主动水平可扩展的实例群上,还是有状态的主动-备用模式,我们都可以使用可用区来实现高水平的可用性。我们部署系统时,确保所有将在故障时需要的容量已完全预置并准备就绪。最后,我们深入探讨了Amazon EC2如何使用静态稳定性概念保持可用区的独立性。

*本文翻译自:Static stability using Availability Zones

profile pictureAWS
支持工程师
Tim
已​发布 1 个月前421 查看次数