亚马逊认为在分布式系统中必须避免使用回退


在分布式系统领域,回退策略是最难应对的挑战之一,对于时间敏感的服务来说尤其如此。更糟糕的是,不良的回退策略可能需要很长时间(甚至数年)才能产生影响,而优质策略与不良策略之间的差异并不明显。本文将重点讲述回退策略如何导致更多问题,且问题的出现速度比修复速度更快。我们将提供一些示例,说明回退策略给 Amazon 哪些方面造成了问题。最后,我们将讨论我们在 Amazon 使用的回退备用方案。

  • 回退逻辑还可能在系统上放置不可预测的负载
  • 回退策略不仅可能会使问题更加严重,而且可能会作为潜在错误发生。

分布式回退在涉及严重系统故障时会出现所有相同的问题,甚至更多的问题。
  • 分布式回退策略更难测试。服务回退比单台计算机应用程序更复杂,因为多台计算机和下游服务在故障中起着重要作用。故障模式本身(如过载方案)很难在测试中复制,即使多台计算机的测试编排随时可用。组合还会增加要测试的案例的数量,因此您需要更多测试,而这些测试的设置会更加困难。
  • 分布式回退策略本身可能会失败。 虽然回退策略似乎可以保证成功,但根据我们的经验,它们通常只能提高成功的几率。
  • 分布式回退策略通常会使中断情况更糟糕。根据我们的经验,回退策略会扩大故障的影响范围,并增加恢复时间。
  • 分布式回退策略通常不值得冒险。与 malloc2 一样,回退策略通常要做出某种权衡;否则,我们会一直使用它。为什么在已经出现问题的情况下还要使用更糟糕的回退策略?
  • 分布式回退策略通常具有潜在的错误,这些错误仅在发生了一组不太可能的巧合时才会出现,可能是在发生后的几个月或几年。Amazon 零售网站中的回退机制触发的实际重大中断说明了所有这些问题。中断发生在 2001 年左右,是由一项新功能导致的,这项新功能为网站上显示的所有产品提供最新的配送速度。

 
Amazon 如何避免回退
  • 提高非回退案例的可靠性

如上所述,回退策略只会降低完全失败的可能性。如果主(非回退)代码的可靠性得到提高,服务的可用性就可能会更高。例如,团队可以投资使用具有更高内在可用性的数据库(例如 Amazon DynamoDB),而不是在两个不同的数据存储之间实施回退逻辑。此策略在 Amazon 中经常使用且屡屡奏效。
  • 让调用者处理错误

严重系统故障的一个解决方案不是回退,而是让调用系统处理故障(例如,通过重试)。这是 AWS 服务的首选策略,我们的 CLI 和开发工具包已经具有内置的重试逻辑。在可能的情况下,我们更青睐这种策略,尤其是在已做出足够努力来共担命运并降低主案例失败可能性(而且回退逻辑根本不可能改善可用性)的情况下。 
  • 主动推送数据

我们用来避免回退的另一种方法是在响应请求时减少移动部件的数量。例如,如果服务需要数据来满足请求,而这些数据已在本地存在(不需要提取),则不需要故障转移策略。这种方法的一个成功示例是实施适用于 Amazon EC2 的 AWS Identity and Access Management (IAM) 角色。IAM 服务需要为 EC2 实例上运行的代码提供经过签名和轮换的凭证。为了避免产生回退需要,系统会主动将凭证推送到每个实例,并在许多小时内保持有效。这意味着由于推送机制发生中断的可能性较小,IAM 角色相关请求可持续工作。 
  • 将回退转换为故障转移

关于回退,最糟糕的其中一件事情是,它不会定期执行,并且在故障期间触发时,可能会失败或扩大影响范围。触发回退的情况可能几个月甚至几年都不会自然发生! 要解决回退策略的潜在失败问题,需在生产环境中定期实施这一策略。服务必须连续运行回退和非回退逻辑。它不能仅运行回退案例,还必须将其视为同等有效的数据源。例如,服务可能会在回退和非回退响应之间随机选择(当同时获得两个响应时),以确保二者都可正常运行。但此时,该策略不能再被视为回退策略,而是完全属于故障转移类别。
  • 确保重试和超时不会成为回退

重试是一种强大的机制,可在出现瞬态和随机错误时提供高可用性。换言之,重试和超时可为因虚假包丢失、不相关的单台计算机故障等小问题而偶尔出现的故障提供保障。但是,重试和超时很容易用错。服务通常持续数月或更长时间,无需多次重试,而在您的团队从未测试过的场景中,这些重试最终可能会投入使用。出于此原因,我们需维护监控总体重试率以及在重试频繁发生时用以提醒团队的警报的指标。
避免让重试变为回退的另一种方法是始终使用主动重试执行操作(也称为对冲或并行请求)。这种技术固有地内置在执行法定读取或写入的系统中,在这种系统中,可能需要三台服务器中的两台服务器提供应答才能响应。主动重试遵循持续工作的设计模式。由于总是发出冗余请求,因此随着对冗余请求的需求增加,不会向系统添加重试产生的额外负载。