DevOps 中处理瞬时故障的 3 种方法

DevOps 旨在通过持续的业务价值来取悦我们的利益相关者,而我们如何管理瞬时故障是其中的一部分。
138 位读者喜欢此文。
What's your DevOps problem?

Opensource.com

在电气工程中,瞬时故障定义为断开电源并恢复后消失的错误情况。 这也是我们许多人在物理设备性能不佳或在充满乱码的蓝色崩溃屏幕上冻结时,强制关闭并重新启动设备时无意识地使用的一种变通方法。

在云计算中,我们面临着日益增长的复杂性、已知的未知数,或者更糟糕的是,我们永远不会接触的基础设施以及以指数级速度发展的技术以及连接不断扩展的数字世界的不同解决方案所带来的未知的未知数。 今天,虚拟用户对无响应、不可靠和性能不佳的产品的容忍度为零——每个人都想要 24x7 正常运行时间以及能够发展并融入其生活方式的解决方案。

在这个新的虚拟世界中,我们不能只是走过去重启机器,至少不能在影响成百上千甚至数百万用户的情况下这样做。 在当今竞争激烈的世界中,对品牌和产品的忠诚度正在迅速下降; 用户可能会点击一下按键寻找替代服务,并且永远不会再回来,而不是忍受任何可以衡量的停机时间。

让我们快速回顾一下两个令人谦卑的事件,它们提醒我们,今天的瞬时故障可能在一瞬间发生,难以识别和解决,并且对我们的利益相关者产生深远的影响。

  • 一段艰难的时期 "在过去的一周半里,我们的服务出现了一些问题。 我对此感到非常难过,并且感到非常抱歉。 这是自我们的服务重构造成不稳定以来,我们遇到的最大的事件,"微软云开发者服务公司副总裁 Brian Harry 在他的博客中写道。 经过数周的不眠之夜,根本原因被确定为对访问控制服务 (ACS) 的请求风暴耗尽了源网络地址转换 (SNAT) 端口,阻止了身份验证,并影响了我们的利益相关者。
  • 503 错误 "从 Azure 函数实现开始设置监控证实了监控在 DevOps 流程中的重要性," Cellenza 的 Mikael Krief 在 ALM DevOps Rangers 博客中报告。 同样,我们花了无数个不眠之夜才找到根本原因,即为什么我们重构的扩展会产生连接和线程风暴,使我们的 Azure 服务崩溃,并因 503 服务不可用错误而让我们的利益相关者感到沮丧。

我们可以为我们的云应用程序设置故障和灾难恢复,以帮助最大限度地减少(而不是消除)由资源故障或自然灾害造成的停机的影响。 但是,对于使用远程资源或与远程服务通信的解决方案,我们需要对瞬时故障增加一些敏感性。 精心设计的解决方案会在发出警报之前检测并尝试自我纠正瞬时故障——或者更糟糕的是,变得无响应并出现故障。

有一些瞬时故障处理模式,包括以下白板上显示的三个:重试限制断路器

transient fault handling patterns

重试模式

重试模式是三种瞬时故障处理模式中最简单的,也是我们在日常生活中自然而然做的事情。 它可以有效地处理跨分布式网络进行通信的解决方案,以处理由网络延迟、服务过载和停电等问题引起的瞬时故障。

Retry pattern

伪代码

设置 failure_count = 0

调用[微]服务

If (fail) failure_count++

If (failure_count > retry_limit) or (not transient failure)失败

延迟(delay_time)

按 failure_count 的因子增加 delay_time

重试步骤 2

该模式确保用户的请求最终会在不理想的情况下成功,否则瞬时故障会导致立即且频繁的故障。 有关详细信息,请参阅 java-design-patterns 和 transient-fault-handling-application-block 等开源实现。

限制模式

我们需要保护我们的服务免受过度使用我们的解决方案或由于系统或逻辑故障而变得不可靠的客户端的侵害。 就像一个四车道的隧道为六车道的高速公路提供服务一样,我们必须管理请求(汽车)的流量并限制超过最大吞吐量(隧道)的端点(车道)。

Throttling pattern

伪代码

增加 request_count

// 限制 – 间隔内的最大请求数

// 降级 – 以“减速”错误失败或暂停操作

If (request_count > limit)
降级服务

调用[微]服务

该模式帮助我们满足服务级别协议,防止单个用户过度使用系统,优化请求流,并处理意外请求的爆发。 我们需要在先前模式中增加重试之间延迟的原因之一是确保我们不会无意中超过系统的吞吐量并触发服务降级。 有关更多详细信息,请参阅 WebApiThrottle 和 Core.Throttling 等开源实现。

断路器模式

就像您家中的断路器一样,断路器模式是您的最后一道防线。 虽然重试模式有助于自动纠正短暂的瞬时故障,但此模式更适合需要更长时间才能解决的瞬时故障。 在处理网络或服务中断时,例如 一段艰难的时期 事件,重试失败的服务操作可能会使情况恶化,导致级联故障,并最终触发解决方案崩溃。 断路器模式的假设是,如果(且仅当)在显着延迟后自动重试,则失败的服务调用才可能成功。

就像您在黑暗中蹒跚地进入地下室寻找断路器柜一样,您允许电气系统和潜在的静电在您拨动开关之前恢复。

Circuit breaker pattern

伪代码

// 断路器未跳闸

If (circuit_state == open)

调用[微]服务

If (
失败) fail_count++

If (fail_count > limit) circuit_state = closed

// 断路器跳闸

Else

If (circuit_state == closed) Start Timer

// 回调定时器事件

On Timer 超时

调用[微]服务

If (success) circuit_state ==
打开

有关更多详细信息,请参阅 Hystrix、circuit-breaker 和 Polly 等开源实现。

不要害怕故障 

请记住包含所有已知故障和已实施处理模式的单元和集成测试。 您的单元测试必须验证您的解决方案在触发故障处理逻辑时是否能做出适当的反应。 另一方面,您的集成测试必须模拟弹性故障,以验证您的集体服务解决方案能否有效地处理该故障。 您可以使用诸如 Hoverfly 之类的服务虚拟化来模拟服务、瞬时故障和降级服务。 如果您的解决方案和相关的故障处理模式未能兑现自我修复和避免灾难性崩溃的承诺,您的利益相关者将不会感到高兴。

因此,像失败一样,故障是 无责备 DevOps 中的一个功能 我们应该 不要害怕它们。 为了保持竞争力,我们必须提高基础设施、解决方案和问责制的质量标准,以便检测、在根本原因级别进行补救,并进行自我纠正以维持可接受的服务级别。

例如,在下图所示中,微服务 #7 崩溃,触发断路器和流量限制,并允许系统恢复,同时继续为用户提供服务。 从这个简单的说明中可以明显看出,故障的组合以及处理它们的难度可能会随着功能标志的切换而变得复杂。

Transient fault example

这些和其他模式是 健康 DevOps 思维方式的核心价值观 之一的强大盟友,即"超越当今流程进行改进——努力始终创新和改进,超越可重复的流程和框架。" 它们帮助我们提高质量标准,并不断提供业务价值并取悦我们的利益相关者。


特别感谢 Brent Reed 的坦率审查和反馈,帮助我们改进和分享我们的见解。

接下来阅读
标签
User profile image.
自80年代中期以来,我一直致力于软件工程的简洁性和可维护性。作为一名软件工程师,我分析、设计、开发、测试和支持软件解决方案。

2 条评论

作为重试策略的一部分,请包含异常处理和其他工具,以便在进行重试尝试时记录。虽然预期的偶尔瞬时故障和重试并不能说明问题,但定期和越来越多的重试通常表明存在可能导致故障的问题,或者当前正在降低应用程序的性能和可用性。
谢谢
https://walmartone.me/

感谢您的宝贵反馈。正如我在示例中提到的,您通常依赖于故障处理策略的组合,例如重试和断路器,以微调系统。关于工具的观点很好,它提供了宝贵的反馈循环,有助于主动监控和根本原因分析。

回复 作者 kelrein

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.