应用程序复原能力模式

提示

此内容摘自电子书《为 Azure 构建云原生 .NET 应用程序》,可在 .NET 文档上获取,也可作为免费可下载的 PDF 脱机阅读。

Cloud Native .NET apps for Azure eBook cover thumbnail.

应用程序复原能力是第一道防线。

虽然你可以投入大量时间来编写你自己的复原框架,但已存在可供使用的此类产品。 Polly 是一个全面的 .NET 复原和暂时性故障处理库,使开发人员能够以流畅且线程安全的方式表达复原策略。 Polly 面向使用 .NET Framework 或 .NET 7 生成的应用程序。 下表介绍了 Polly 库中提供的名为 policies 的复原功能。 它们可以单独应用,也可以组合在一起应用。

策略 体验
重试 配置对指定操作的重试操作。
断路器 当故障超过配置的阈值时在预定义的时段内阻止请求的操作
超时 限制调用方可以等待响应的持续时间。
隔舱 将操作约束到固定大小的资源池,从而防止因淹没资源的调用失败。
缓存 自动存储响应。
回退 定义发生故障时的结构化行为。

请注意上图中复原策略是如何应用于请求消息的,无论是来自外部客户端还是后端服务。 目的是对可能暂时不可用的服务的请求进行补偿。 通常,这些短期的中断会通过下表中所示的 HTTP 状态代码自行显现出来。

HTTP 状态代码 原因
404 未找到
408 请求超时
429 请求过多(你可能已受到限制)
502 网关错误
503 服务不可用
504 网关超时

问:是否要重试 HTTP 状态代码 403 - 已禁止? 错误。 此时,系统是正常运行的,但会通知调用方,告知他们无权执行请求的操作。 务必要注意的是,仅重试由失败导致的那些操作。

按照第 1 章中的建议,构造云原生应用程序的 Microsoft 开发人员应以 .NET 平台为目标。 版本 2.1 引入了 HTTPClientFactory 库,用于创建用于与基于 URL 的资源进行交互的 HTTP 客户端实例。 通过取代原始 HTTPClient 类,工厂类支持许多增强的功能,其中一项功能与 Polly 复原库紧密集成。 通过此功能,你可以轻松地在应用程序 Startup 类中定义复原策略来处理部分故障和连接问题。

接下来,让我们来仔细了解一下重试和断路器模式。

重试模式

在分布式云原生环境中,对服务和云资源的调用可能会因暂时性(短期)故障而失败,这些故障通常会在一小段时间后自行纠正。 实现重试策略可帮助云原生服务缓解这些情况。

重试模式使服务能够多次(可配置)重试失败的请求操作,且等待时间呈指数增加。 图 6-2 显示了一个重试操作。

Retry pattern in action

图 6-2. 生效中的重试模式

在上图中,为一个请求操作实现了一个重试模式。 此重试模式配置为在失败之前允许最多四次重试,退避时间间隔(等待时间)开始为两秒,对于后续的每次尝试,此间隔时间呈指数翻倍增加。

  • 第一次调用失败并返回 HTTP 状态代码 500。 应用程序会等待两秒,然后重试调用。
  • 第二次调用也失败了,返回 HTTP 状态代码 500。 此时,应用程序的退避时间间隔将翻倍增加到四秒,然后再重试调用。
  • 最后,第三次调用成功了。
  • 在此方案中,重试操作在调用失败之前最多尝试四次重试,同时,退避持续时间将翻倍。
  • 假如第四次重试尝试失败了,将调用回退策略来妥善处理此问题。

有一点至关重要,即应该增加重试调用之前的退避时间段,给予服务足够的时间进行自我纠正。 最佳做法是实现呈指数增加的退避(在每次重试时使此时段翻倍),从而得到足够的纠正时间。

断路器模式

尽管重试模式有助于对部分失败中所涉及的请求进行补救,但是在某些情况下,意外的事件可能会导致失败,这需要更长的时间才能解决。 这些故障轻则导致部分连接中断,重则导致服务完全瘫痪。 在这些情况下,应用程序持续重试一个操作是毫无意义的,因为重试不太可能会成功。

更糟糕的是,对未响应的服务执行连续的重试操作可能会让你陷入自行造成的拒绝服务情况,在这种情况下,你的服务会被连续调用所淹没,内存、线程和数据库连接等资源将耗尽,这将导致系统上使用相同资源的不相关部分出现故障。

在这些情况下,更好的做法是让操作立即失败,并且仅尝试调用可能会成功的服务。

断路器模式可以防止应用程序重复尝试执行可能会失败的操作。 在预定义的失败调用数后,它会阻止到服务的所有流量。 它允许定期尝试进行调用以确定故障是否已解决。 图 6-3 显示了生效中的断路器模式。

Circuit breaker pattern in action

图 6-3。 生效中的断路器模式

在上图中,已向原始重试模式添加了一个断路器模式。 请注意,在 100 次失败的请求后,断路器将打开,不允许再对服务进行调用。 CheckCircuit 值设置为 30 秒,指定库允许向服务发送一个请求的频率。 如果该调用成功,断路器将关闭,流量可以再次传输到服务。

请记住,断路器模式的目的与重试模式的目的不同。 重试模式使应用程序能够重试预期将成功的操作。 断路器模式阻止应用程序执行可能会失败的操作。 通常,应用程序会将这两种模式结合起来,通过断路器使用重试模式来调用操作。

测试复原能力

测试复原能力的方式并非始终与测试应用程序功能的方式(通过运行单元测试、集成测试等)相同。 相反,必须测试端到端工作负载在故障状态下的表现,而这种状态只会间歇性地出现。 例如:由崩溃的进程造成的注入失败、过期的证书,以及从属服务不可用等。可以使用 chaos-monkey 等 Framework 来进行此类混沌测试。

对于处理有问题的请求操作,应用程序必须具有复原能力。 不过,我们的旅程才进行到一半。 接下来,我们将介绍 Azure 云中提供的复原功能。