可用性核对清单

模式和实践

应用程序设计

  • 避免任何单点故障。 为避免单点故障影响可用性,应该将所有组件、服务、资源和计算实例部署为多个实例。 这包括身份验证机制。 将应用程序设计为可配置为使用多个实例,自动检测失败,并将请求重定向到未失败的实例(平台并不在其中自动执行此操作)。
  • 根据不同的服务级别协议分解工作负荷。 如果服务由重要和比较不重要的工作负荷组成,请以不同的方式进行管理,并指定服务功能和实例数,以符合其可用性要求。
  • 最小化和了解服务依赖项。 尽可能将使用过的不同服务数降到最低,并确保了解所有存在于系统中的功能和服务依赖项, 包括这些依赖项的性质、失败造成的影响,或整个应用程序上每个服务降低的性能。 Microsoft 保证大多数服务至少提供 99.9% 的可用性,但这意味着应用程序依赖的其他每个服务可能降低 0.1% 的系统整体可用性 SLA。
  • 尽可能将任务和消息设计为幂等(安全重复),使重复的请求不会导致问题。 例如,服务可以充当处理消息的使用者,这些消息由系统中充当生成者的其他部分发送为请求。 如果使用者在处理消息之后、确认消息已处理之前失败,生成者可以提交重复请求,由使用者的另一个实例处理。 出于此原因,使用者与它们执行的操作应该具有幂等性,以便重复以前执行的操作不会使结果无效。 这可能意味着要检测重复消息或使用乐观方法来处理冲突以确保一致性。
  • 使用消息代理来为重要事务实现高可用性。 用于启动任务或访问远程服务的许多方案都使用消息传送在应用程序与目标服务之间传递指令。 为了获得最佳性能,应用程序应该能够发送消息,然后返回以处理更多请求,而无需等待回复。 若要保证传送消息,消息传送系统应提供高可用性。 Azure 服务总线消息队列实现 至少一次 语义。 这意味着,发布到队列的每个消息都不会丢失,不过在某些情况下可能会发送重复的副本。 如果消息处理是幂等的(请参阅前一项),则重复传送应该不是问题。
  • 将应用程序设计为在达到资源限制时适当降级 ,并采取适当的措施将对用户的影响降到最低。 在某些情况下,应用程序上的负载可能超出一个或多个部件的容量,导致降低可用性和连接失败。 缩放有助于缓解此问题,但可能会达到资源可用性或成本等其他因素施加的限制。 将应用程序设计为可在此情况下自动适当地降级。 例如,在电子商务系统中,如果订单处理子系统处于高压状态(甚至完全故障),可以暂时禁用该子系统,同时允许其他功能(例如浏览产品目录)继续工作。 适当的做法是延后对故障子系统发出的请求,例如,仍然允许客户提交订单,但同时要保存订单,以便在订单子系统稍后再次可用时进行处理。
  • 适当处理急剧突发事件。 大多数应用程序需要处理不同时间的不同工作负荷,例如业务应用程序中上午出现的第一波高峰,或者电子商务网站中发布新产品时。 自动缩放有助于处理负载,但可能需要一些时间使其他实例联机并处理请求。 通过将应用程序设计为将请求加入其使用的服务队列,并在队列接近完全容量时适当降级,以防止突发和意外的活动高峰导致超出应用程序的处理能力。 确保有足够的性能和容量可供非高峰条件清空队列和处理未完成的请求。 有关详细信息,请参阅 基于队列的负载调节模式

部署和维护

  • 为每个服务部署角色的多个实例。 Microsoft 提供为你创建和部署的服务提供可用性保证,但这些保证的有效前提是必须在服务中为每个角色部署至少两个实例。 这样,其中一个角色可以不可用,而另一个实例保持活动状态。 如果想要将更新部署到实时系统而不中断客户端的活动,这项保证就特别重要;实例可以单独中断和升级,而其他实例将继续保持联机。
  • 在多个数据中心托管应用程序。 整个数据中心可能因为自然灾害或 Internet 故障等事件而脱机,不过这种情况极其少见。 至关重要的业务应用程序应该托管在多个数据中心,以提供最大的可用性。 这样做还可以减少本地用户的延迟,并在更新应用程序时进一步提供弹性。
  • 自动化和测试部署与维护任务。 分布式应用程序由多个必须共同工作的部件组成。 因此,部署应该使用经过测试和证实的机制(例如脚本和部署应用程序)来自动化。 这些脚本和应用程序可更新并验证配置,以及自动化部署过程。 自动化技术还应该用于执行全部或部分应用程序的更新。 务必全面测试所有过程,以确保错误不会导致其他停机情况。 所有的部署工具必须有适当的安全限制,以保护部署的应用程序;慎重定义和强制实施部署策略,并将人为介入的需要降到最低。
  • 考虑使用平台的过渡和生产功能 ,其中包括上述所有功能。 例如,使用 Azure 云服务过渡与生产环境可使应用程序通过虚拟 IP 地址交换(VIP 交换)的方式即时相互切换。 但是,如果想要在本地过渡,或者同时部署应用程序的不同版本并逐渐迁移用户,则你可能无法使用 VIP 交换操作。
  • 在不回收实例的情况下应用配置更改 。 在许多情况下,可以更改 Azure 应用程序或服务的配置设置,而无需重新启动角色。 角色公开可以处理的事件以检测配置更改,并将其应用到应用程序中的组件。 但是,对核心平台设置所做的某些更改需要重新启动角色。 在构建组件和服务时,通过将其设计为可接受配置设置的更改而无需重新启动整个应用程序,来最大化可用性并将停机时间减到最小。
  • 在更新期间使用升级域实现零停机时间。 Azure 计算单元(如 Web 角色和辅助角色)已配置到升级域。 升级域将角色实例分组在一起,因此,在发生滚动更新时,升级域中的每个角色都将轮流停止、更新并且重新启动。 这可以最大程度地减小对应用程序可用性的影响。 你可以指定在部署服务时,应该为服务创建几个升级域。

    Note

    角色还分布在容错域中,每个容错域在服务器机架、电源和散热预配等方面彼此相当独立,以便将故障影响所有角色实例的可能性降到最低。 这种分布是自动发生的,你无法控制它。

  • 配置 Azure 虚拟机的可用性集。 将两个或更多个虚拟机放在同一个可用性集中可保证这些虚拟机不会部署到同一个容错域。 若要最大化可用性,应该为系统使用的每个重要虚拟机创建多个实例,并将这些实例放在同一个可用性集中。 如果你正在运行多个满足不同目的的虚拟机,请为每个虚拟机创建可用性集。 将每个虚拟机的实例添加到每个可用性集。 例如,如果你已创建不同的虚拟机来充当 Web 服务器和报告服务器,请为 Web 服务器创建一个可用性集,并为报告服务器创建另一个可用性集。 将 Web 服务器虚拟机的实例添加到 Web 服务器可用性集,并将报告服务器虚拟机的实例添加到报告服务器可用性集。

数据管理

  • 利用数据复制 。 Azure 存储中的数据会自动复制,以防止基础结构故障时发生数据丢失,你可以配置这种复制的某些方面。 例如,可以在多个地理区域中复制数据的只读副本(称为全局读取访问冗余存储,简称 RA-GRS)。 请注意,使用 RA-GRS 会产生额外的费用。 有关详细信息,请参阅 Azure Storage Pricing(Azure 存储定价)。
  • 使用乐观并发访问和最终一致性 。 通过锁定(悲观并发)阻止访问资源的事务可能会导致性能不佳,并大幅降低可用性。 这些问题在分布式系统中可能会变得特别严重。 在许多情况下,谨慎的设计和方法(例如分区)可以将发生更新冲突的可能性降到最低。 复制数据或者从独立更新的存储中读取数据时,数据只会保持最终一致性。 但其优点通常超越了使用事务来确保即时一致性所导致的可用性影响。
  • 使用定期备份和时间点还原,并确保符合恢复点目标 (RPO)。 定期自动备份未保留在其他位置的数据,并确认可以在发生故障时可靠还原数据和应用程序本身。 数据复制并不是备份功能,因为故障、错误或恶意操作造成的错误和不一致性将会复制到所有存储中。 备份过程必须是安全的,这样才能保护传输中和存储中的数据。 数据库或部分数据存储通常可以使用事务日志恢复到以前的某个时间点。 Azure 为存储在 Azure SQL 数据库中的数据提供备份工具。 数据将导出到 Azure Blob 存储上的备份包,并且可下载到存储的安全本地位置。
  • 启用高可用性选项来维护 Azure Redis 缓存的辅助副本。 使用 Azure Redis 缓存时,请选择“标准”选项来维护内容的辅助副本。有关详细信息,请参阅 在 Azure Redis 缓存中创建缓存

错误和故障

  • 引入超时的概念。 服务和资源可能会变为不可用,导致请求失败。 请确保应用的超时适合每个服务或资源,以及访问服务或资源的客户端。 (在某些情况下,对特定的客户端实例允许较长的超时可能比较合适,具体取决于客户端正在执行的上下文和其他操作。)太短的超时可能对产生较长延迟的服务和资源造成过多的重试操作。 如果大量的请求正在排队等待服务或资源做出响应,则很长的超时可能会导致阻塞。
  • 重试暂时性故障导致的失败操作。 设计重试策略,以便在所有服务和资源原本不支持自动连接重试的情况下访问这些服务和资源。 使用适当的策略,规定随着故障次数的增加,每两次重试的间隔延迟时间也会增加,以避免资源过载,并允许资源正常恢复和处理排队的请求。 以很短的延迟连续重试可能会使问题恶化。
  • 停止发送请求以避免级联故障 。 在某些情况下,暂时性故障或其他故障(严重性范围从部分连接断开到服务完全故障)花费比预期更长的时间才能恢复正常。 此外,如果服务非常繁忙,系统中某个部件的故障可能会导致级联故障,并导致许多操作在占用重要系统资源(例如内存、线程和数据库连接)时遭到阻止。 应用程序不应连续重试不太可能成功的操作,而应快速接受操作失败的事实,并适当地处理这种失败。 可以使用断路器模式在定义的时间段内拒绝对特定操作的请求。 有关详细信息,请参阅 Circuit Breaker Pattern(断路器模式)。
  • 组建或故障回复到多个组件 以缓解特定服务脱机或不可用所造成的影响。 将应用程序设计为尽可能利用多个实例且不影响操作和现有连接。 使用多个实例并分散它们之间的请求,检测并避免向故障的实例发送请求,以便最大化可用性。
  • 故障回复到不同的服务或工作流 。 例如,如果写入 SQL 数据库失败,请暂时将数据存储在 Blob 存储中。 提供一个工具用于在服务可用时将 Blob 存储中的数据重新写入 SQL 数据库。 在某些情况下,失败的操作可能有替代操作允许应用程序继续工作,即使组件或服务发生故障。 如果可能,请检测故障并将请求重定向到其他可提供适当替代功能的服务,或者在主服务脱机时,备份或减少可保持核心操作的功能实例。

监视和灾难恢复

  • 针对可能的故障和故障事件提供丰富的检测 ,以将情况汇报给操作人员。 针对可能但尚未发生的故障提供足够的数据,以便操作人员确定其原因,缓解局面,并确保系统保持可用。 针对已发生的故障,应用程序应该将适当的错误消息返回给用户,但仍然尝试继续运行,尽管功能降低。 在各种情况下,监视系统应该捕获完整的详细信息,以便操作人员实施快速恢复,并根据需要让设计人员和开发人员修改系统,以防止再次发生此情况。
  • 通过实施检查功能来监视系统运行状况。 应用程序的运行状况和性能可能在不同时间出现不明显的降级,直到发生故障为止。 实施探测或定期从应用程序外部执行检查功能。 这些检查与度量整个应用程序、应用程序的单个部件、应用程序使用的单个服务和单个组件的响应时间一样简单。 检查功能可以一些进程来确保生成有效的结果、度量延迟、检查可用性,并从系统中提取信息。
  • 定期测试所有故障转移和故障回复系统 ,以确保它们可用并按预期工作。 对系统和操作的更改可能会影响故障转移和故障回复功能,但是在主系统发生故障或过载之前可能无法检测到这种影响。 先测试系统,以防在运行时弥补实时问题。
  • 测试监视系统。 自动化故障转移和故障回复系统,以及使用仪表板手动进行系统运行状况和性能可视化,都依赖于监视和检测功能的正常运行。 如果这些元素发生故障、遗漏重要信息或报告错误的数据,操作人员可能不知道系统不正常或即将发生故障。
  • 跟踪长时间运行的工作流的进度 并在发生故障时重试。 长时间运行的工作流通常由多个步骤组成。 确保每个步骤都是独立且可以重试的,以最大程度地减少整个工作流需要回滚,或需要执行多个补偿事务的可能性。 通过实施一种模式,如 计划程序代理监督程序模式模式,监视和管理长时间运行的工作流的进度。
  • 规划灾难恢复。 对于可能导致主系统全部或部分不可用的任何类型的故障,请确保有记录、接受和经过全面测试的计划。 定期测试这些恢复过程,并确保所有操作人员熟悉相关过程。