在设计时确保可扩缩性和高可用性

Last reviewed 2023-08-05 UTC

本文档在 Google Cloud 架构框架中,提供了在设计服务架构时需要遵循的设计原则,使这些服务能够容忍故障并根据客户需求进行缩容。当服务需求较高或发生维护事件时,可靠的服务将能够继续响应客户请求。以下可靠性设计原则和最佳实践应该是系统架构和部署计划的一部分。

创建冗余以实现更高的可用性

具有高可靠性需求的系统必须避免单点故障,并且必须在多个故障网域之间复制其资源。故障域是可以单独出现故障的资源池,例如虚拟机实例、可用区或地区。跨故障网域进行复制时,您可以获得高于单个实例可以达到的总体可用性水平。如需了解详情,请参阅地区和可用区

作为可能属于系统架构的一个具体冗余示例,如需将 DNS 注册过程中的故障隔离到个别区域,请为同一网络中的实例使用区域级 DNS 名称以互相访问。

设计具有故障切换功能的多可用区架构以实现高可用性

您可以将应用的架构设计为使用分布在多个可用区中的资源池,并在可用区之间复制数据、进行负载均衡和自动执行故障切换,从而使应用灵活应对区域级故障。运行应用堆栈每一层的区域级副本,并消除架构中的所有跨可用区依赖项。

跨区域复制数据以进行灾难恢复

将数据复制或归档到远程地区,以便在发生地区级服务中断或数据丢失时进行灾难恢复。在使用复制功能时,除了因复制延迟而可能丢失少量数据之外,远程区域中的存储系统已经具有几乎最新的数据,因此恢复速度会更快。使用定期归档而非持续复制时,灾难恢复涉及从新区域的备份或归档中恢复数据。此过程通常会导致服务停机时间比激活持续更新的数据库副本更长,并且可能因连续备份操作之间的时间间隔而造成数据丢失。无论使用何种方法,整个应用堆栈都必须重新部署并在新区域中启动,并且在发生这种情况时服务将不可用。

如需详细了解灾难恢复概念和技术,请参阅针对云基础架构服务中断设计灾难恢复架构

设计多区域架构以灵活应对区域级服务中断

如果您的服务需要在整个区域出现故障的罕见情况下持续运行,请将其设计为使用分布在不同区域的计算资源池。 运行应用栈每一层的地区级副本。

跨地区使用数据复制,并在地区发生故障时进行自动故障切换。某些 Google Cloud 服务具有多区域变体,例如 Spanner。为应对区域级故障,请在设计中尽可能使用这些多区域服务。如需详细了解地区和服务可用性,请参阅 Google Cloud 位置

确保不存在跨地区的依赖项,使得将地区级故障的影响范围限制在该地区。

消除地区级单点故障,例如在无法访问时可能导致全球服务中断的单个地区主数据库。请注意,多区域架构的费用通常较高,因此在采用此方法之前,请综合考虑业务需求与费用。

如需进一步了解如何跨故障域实现冗余,请参阅云应用的部署原型 (PDF) 调查问卷。

消除可伸缩性瓶颈

识别无法超越单个虚拟机或单个区域资源限制的系统组件。某些应用会垂直扩缩,在其中,您可以在单个虚拟机实例上添加更多 CPU 核心、内存或网络带宽以处理负载增加的情况。这些应用对可伸缩性有严格的限制,并且您必须经常手动对其进行配置以处理增长。

如果可能,请将这些组件重新设计为横向扩缩,例如使用分片或分区,跨虚拟机或可用区扩缩。如需处理流量或使用量增长,添加更多分片即可。使用标准虚拟机类型,可自动添加以处理每个分片的负载增长。如需了解详情,请参阅构建可扩缩且弹性佳的应用时应遵循的模式

如果您无法重新设计应用,则可以将自行管理的组件替换为无需用户操作即可横向扩缩的全托管式云服务。

过载时逐步降低服务级别

设计您的服务以承受过载。服务应该检测过载,并向用户返回降低质量的响应或减少部分流量,而不是在遇到过载时完全不能工作。

例如,服务可以使用静态网页响应用户请求,并暂时停用处理费用较昂贵的动态效果。从 Compute Engine 到 Cloud Storage 的热故障切换模式中详细介绍了此行为。或者,服务可以允许执行只读操作并暂时停用数据更新。

当服务降级时,应通知操作员以纠正错误情况。

预防和缓解流量峰值

请不要跨客户端同步请求。太多客户端在同一时刻发送流量会导致流量高峰,从而会导致级联故障。

在服务器端实施高峰缓解策略,例如限制、排队减载熔断优雅降级确定关键请求的优先级

客户端上的缓解策略包括客户端限制和使用抖动的指数退避算法。

清理并验证输入

为了防止会导致服务中断或安全漏洞的错误、随机或恶意输入,请清理并验证 API 和操作工具的输入参数。例如,Apigee 和 Google Cloud Armor 有助于防范注入攻击

定期使用模糊测试,其中自动化测试框架会有意使用随机、空的或过大的输入调用 API。在隔离的测试环境中进行这些测试。

操作工具应在更改发布之前自动验证配置更改,如果验证失败,则应拒绝更改。

以可以保留功能的方式进入故障安全模式

如果问题导致发生故障,系统组件应以可让整个系统继续运行的方式发生故障。这些问题可能为软件错误、输入或配置有误、计划外实例中断或人为错误。您的服务流程有助于确定您应该是过于宽松或过于简单,而不是过于限制。

请考虑以下示例场景以及应对故障的方法:

  • 一般而言,最好是让配置错误或为空的防火墙组件故障打开,并允许未经授权的网络流量在操作员修复错误期间短时间通过。此行为可让服务保持可用,而不是故障关闭并阻止所有流量。该服务必须依靠应用栈中更深层次的身份验证和授权检查,在所有流量都通过时保护敏感区域。
  • 但是,最好让控制用户数据访问的权限服务器组件故障关闭并阻止所有访问。当配置损坏时,此行为会导致服务中断,但可在故障打开时避免机密用户数据泄露的风险。

在这两种情况下,故障都应引发高优先级提醒,以便操作员可以解决错误情况。服务组件应偏于故障打开,除非这会对业务造成极大的风险。

将 API 调用和操作命令设计为可重试

API 和操作工具必须尽可能确保重试安全。处理许多错误情况的自然方法是重试以前的操作,但您可能不知道第一次尝试是否成功。

您的系统架构应使操作具有幂等性 - 如果您对一个对象连续执行两次或多次相同的操作,则应该会产生与单次调用相同的结果。非幂等性操作需要更复杂的代码,以避免系统状态损坏。

识别和管理服务依赖项

服务设计人员和所有者必须维护对其他系统组件的依赖项的完整列表。服务设计还必须包括从依赖项故障中恢复,或者如果完全恢复不可行,则优雅降级。考虑系统和外部依赖项(如第三方服务 API)使用的云服务的依赖项,识别具有非零故障率的每个系统依赖项。

设置可靠性目标时,请注意服务的 SLO 受其所有关键依赖项的 SLO 的数学约束。您的可靠性不会高于其中一个依赖项的最低 SLO。如需了解详情,请参阅服务可用性计算

启动依赖项

与稳定状态行为相比,服务在启动时的行为会有所不同。启动依赖项可能与稳定状态运行时依赖项大不相同。

例如,启动时,服务可能需要从它很少再次调用的用户元数据服务加载用户或账号信息。如果许多服务副本在发生崩溃或例行维护后重启,则副本会严重增加启动依赖项的负载,尤其是在缓存为空且需要重新填充时。

测试服务在负载下启动,并相应地预配启动依赖项。考虑这样的设计:通过保存从重要启动依赖项中检索的数据的副本逐步将设计降级。此行为使您的服务可以使用可能过时的数据重启,而不是在关键依赖项中断时无法启动。在可行的情况下,您的服务稍后可以加载最新数据,以恢复正常运行。

在新环境中引导服务时,启动依赖项也很重要。设计应用堆栈并采用分层架构,各个层之间没有循环依赖关系。循环依赖关系可能看似可容忍,因为它们不会阻止对单个应用的增量更改。但是,循环依赖关系可能会使得在灾难使整个服务堆栈崩溃后难以或无法重启。

最大限度地减少关键依赖项

最大限度地减少服务的关键依赖项数量,即其故障不可避免地导致服务中断的其他组件。为了使您的服务能够更灵活地应对其依赖的其他组件中的故障或运行缓慢的问题,请考虑以下示例设计技术和原则,将关键依赖项转换为非关键依赖项:

  • 提高关键依赖项的冗余级别。添加更多副本,从而降低整个组件变得不可用的可能性。
  • 使用对其他服务的异步请求,而不是阻止响应,或使用发布/订阅消息功能将请求与响应分离。
  • 缓存其他服务的响应,以从依赖项的短期不可用状态中恢复。

为使服务中故障或运行缓慢现象对依赖它的其他组件的影响较小,请考虑以下示例设计技术和原则:

  • 使用具有优先次序的请求队列,并优先处理用户正在等待响应的请求。
  • 从缓存中提供响应,以减少延迟时间和负载。
  • 以可以保留功能的方式进入故障安全模式。
  • 在流量过载时逐步降级。

确保可以回滚所有更改

如果没有明确定义的方法来撤消对服务进行的某些类型的更改,请更改服务的设计以支持回滚。应定期测试回滚流程。必须对每个组件或微服务的 API 进行版本控制,并且它们必须具有向后兼容性,使得上一代客户端继续随着 API 的发展而正常运行。此设计原则对于允许逐步发布 API 更改至关重要,可在必要时快速回滚。

对于移动应用而言,实现回滚的成本可能很高。Firebase Remote Config 是一项 Google Cloud 服务,可简化功能回滚。

您无法轻松回滚数据库架构更改,因此请分多个阶段执行。设计每个阶段,以允许按最新版本的应用和先前版本进行安全架构读取和更新请求。这种设计方法让您可以在最新版本出现问题时安全地回滚。

建议

如需将架构框架中的指导运用到您自己的环境,请遵循以下建议:

  • 在客户端应用的错误重试逻辑中实现随机化指数退避算法。
  • 实现具有自动故障切换功能的多区域架构,以实现高可用性。
  • 使用负载均衡功能在分片和地区之间分布用户请求。
  • 将应用设计为在过载时逐步降级。提供部分响应或提供有限功能,避免完全停止工作。
  • 建立容量规划的以数据为依据的流程,并使用负载测试和流量预测来确定何时预配资源。
  • 制定灾难恢复程序并定期进行测试。

后续步骤

探索架构框架中的其他类别,例如系统设计、卓越运营以及安全性、隐私权和合规性。