应用程序和基础结构复原能力
复原能力是指从暂时性故障中恢复的能力。 应用的恢复策略会恢复正常功能且将对用户的影响降到最低。 云环境中可能会发生故障,应用应以尽可能减少停机时间和数据丢失的方式做出响应。 理想情况下,你的应用可以在用户根本就觉察不到问题的情况下正常完成故障的处理。
由于微服务环境可能不稳定,因此在设计应用时要使其能够预期并处理部分故障。 部分故障的示例可能包括代码异常、网络中断、服务器进程无响应或硬件故障。 即使是计划内的活动(例如将容器移到 Kubernetes 群集中的其他节点)也可能会导致暂时性故障。
复原方法
在设计可复原的应用程序时,通常需要在快速失败和正常降级之间进行选择。 快速失败意味着应用程序会在出现问题时立即引发错误或异常,而不是尝试恢复或解决问题。 这样就可以快速识别和修复问题。 正常降级意味着即使某些组件发生故障,应用程序也会尝试保持以有限的容量运行。
在云原生应用程序中,服务必须正常处理故障,而不是快速失败。 由于微服务是分散的且可独立部署,因此预计会出现部分故障。 快速失败可导致因一个服务出现故障而快速关闭相关服务,从而降低整体系统复原能力。 而微服务则应进行相应编码,以便能够预测和容忍内部和外部服务故障。 这种正常降级允许整个系统继续运行,即使部分服务中断。 这样,面向用户的关键功能可以继续使用,避免完全中断。 正常故障还能让受干扰的服务有时间进行恢复或自我修复,而不至于影响系统其他部分。 因此,对于基于微服务的应用程序,正常降级更符合故障隔离和快速恢复等复原最佳做法。 它可防止本地事件发生跨系统级联。
有两种基本方法支持具有复原能力的正常降级:应用程序和基础结构。 每种方法都有其优点和缺点。 哪种方法合适视情况而定。 此模块介绍如何实现基于代码和基于基础结构的复原。
基于代码的复原
为了实现基于代码的复原能力,.NET 具有一个用于实现复原和暂时性故障处理的扩展库 Microsoft.Extensions.Http.Resilience
。
它以线程安全的方式使用流畅、易于理解的语法构建故障处理代码。 有几种复原策略用来定义故障处理行为。 在此模块中,你将向 HTTP 客户端操作应用重试和断路器策略。
重试策略
顾名思义,重试策略表示重试。 如果收到错误响应,则在短暂等待后重试该请求。 每次重试时,等待时间都会增加。 这种增加可以是线性的或指数形式的。
达到最大重试次数后,策略会放弃并引发异常。 从用户的角度来看,应用通常需要更长的时间来完成某些操作。 应用可能还需要一些时间才能通知用户无法完成操作。
断路器策略
断路器策略通过暂停尝试与目标服务的通信,使其在多次失败后中断。 该服务可能遇到严重问题,暂时无法响应。 在达到指定的连续失败次数后,连接尝试将暂停,从而“断开”线路。。 在此等待期间,目标服务上的其他操作会立即失败,甚至无需尝试连接该服务。 等待时间过后,将再次尝试该操作。 如果服务成功响应,则线路“闭合”,系统恢复正常。
基于基础结构的复原
若要实现基于基础结构的复原,可使用服务网格。 除了无需更改代码的复原能力,服务网格还提供流量管理、策略、安全性、强标识和可观测性。 你的应用与移动到基础结构层的操作功能分离。
与基于代码的方法的比较
基于基础结构的复原方法可以使用基于指标的视图,以便实时动态适应群集条件。 此方法会再添加一个维度来管理群集,但不会添加任何代码。
使用基于代码的方法:
- 需要猜测适合采用哪些重试和超时参数。
- 应关注特定的 HTTP 请求。
没有合理的方法来响应应用代码中的基础结构故障。 考虑同时处理的数百个或数千个请求。 即使是指数回退(时间请求计数)的重试也可能会使服务不堪负重。
相比之下,基于基础结构的方法不了解应用内部。 例如,复杂的数据库事务对于服务网格是不可见的。 此类事务的故障保护只能采用基于代码的方法。
在接下来的单元中,你将在代码和 Linkerd 服务网格中使用 .NET HTTP 复原为基于微服务的应用实现复原能力。