如何避免分布式服务中的“重试风暴”?


10

当客户端配置为在放弃之前重试设置的次数后,将导致“重试风暴”,因为在服务的正常操作中会发生数据包丢失,所以需要重试策略。

举个例子:

样例架构

例如,如果将整个服务扩展到每秒支持80,000个请求并以大约80%的容量运行,那么导致该服务每秒接收101,000个请求的流量高峰将导致其中1,000个请求失败。

当重试策略启动时,您最终会收到额外的1,000多个请求,具体取决于检测到故障的位置,从而将整个服务每秒提高至102,000个请求-从那里,您的服务进入死亡螺旋状,数量翻倍每秒失败的请求数量。

除了在预计的高峰交易之后大量超额提供服务之外,这将是低效的。您可以采用什么策略来避免“重试风暴”?


如果100kQPS是容量的80%,那么101kQPS不应导致1000失败,而应该导致零失败-这不是过度配置的重点吗?
阿德里安

@Adrian,您的权利,这是一个解释这个观点的人为例子-我试图简化一下,以使我的观点清晰而又不过分抽象。我已将“缩放至支持100,000”更正为“缩放至支持80,000”。
理查德·斯莱特

Answers:


7

这取决于您要避免的情况。

如果您要避免对真正关键的服务进行任何服务中断(我在考虑“如果不适当地服务我的API调用,人们将会丧命”),则您需要为巨大的低效率做些预算来自大量的调配专用资源。是的,它们必须是专用的,所有这些都不会导致流量高峰,多个服务峰值会因此导致中断。

更可能的情况是你服务下去会带来不便,你既可以从客户端和服务器端解决这个问题。尽管值得注意的是,实际上无法解决大量流量的问题在逻辑上是不可能的,因为如果不处理流量(消耗资源),就无法知道是否重试,如果是成功但错误处理的请求的重试客户端(如果是DDOS等),则可以减轻影响。

客户端代码中编写合理的重试逻辑,该逻辑具有上限和正常失败的机制。这样,您就不会让用户陷入失败请求的无限循环中,而只是给他们一个错误,告诉他们在短时间内尝试他们所做的任何事情。

对于您的服务器端基础架构,最简单的解决方案是限制。对请求的硬限制,特别是如果您可以尝试根据特定用例合理地扩展它们(例如,如果您拥有集中式服务做出一些硬决策,是否要开始阻止地理位置遥远的请求,这可能导致线程挂起)服务器端?还是您要平均分配不可避免但很小的中断?等)基本上可以归结为以下事实:有意从网关返回503比让请求通过并发送504便宜得多无论如何。基本上强迫客户根据您当前提供的内容行事并提供正确的响应,以便客户可以做出适当的反应。


5

防止这些重试风暴的一种方法是使用退避机制。

从Google App Engine 规模设计指南的实施重试实现部分中:

无论是使用URL Fetch还是Socket API调用Cloud Datastore之类的服务或外部服务,您的代码都可以重试失败。在这些情况下,您应始终实施随机指数退避策略,以避免出现雷电群问题。您还应限制重试的总数,并在达到最大重试限制后处理失败。

默认情况下,大多数GAE API已经具有此类退避机制/策略。


谢谢,实现退避机制是一个很好的建议,我通常会使用“ 瞬时故障处理应用程序块”进行可配置的指数退避。但是,通过5年以上在Azure中运行超大规模应用程序的运营经验,即使出现了指数级的退缩,“重试风暴”仍然经常发生-我一直无法找到一种可行的避免此类攻击的策略。
理查德·斯莱特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.