当客户端配置为在放弃之前重试设置的次数后,将导致“重试风暴”,由于在服务的正常运行中会发生数据包丢失,因此需要重试策略。例如:



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

当重试策略启动时,最终会产生另外1,000个请求,具体取决于检测到故障的位置。整个服务每秒最多可处理102,000个请求-从那里您的服务进入死亡螺旋,每秒失败请求的数量增加一倍。高峰交易,这将是低效的。您可以采用什么策略来避免“重试风暴”?

评论

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

@Adrian,您的权利,这是一个解释这个问题的人为例子-我正试图简化一下以使我的观点清晰,而又不过分抽象。我已将“扩展到支持100,000”改正为“扩展到支持80,000”。

#1 楼

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

如果您要避免对真正重要的服务进行任何服务中断(我在想的是“如果我API调用不能得到适当的服务”),您只需要为因过度配置专用资源而造成的巨大效率预算。是的,它们必须专心致志,所有这些都不会引起流量高峰,因此多种服务峰值会导致服务中断。您可以从客户端和服务器端解决问题。尽管值得注意的是,从逻辑上讲,实际上不可能解决大量流量的问题,因为如果不处理流量(消耗资源),您将无法知道是否重试,如果是成功但错误处理的请求的重试由客户端(如果是DDOS等)来实现。但是您可以减轻影响。这样,您就不会让用户陷入失败请求的无限循环,而只是给他们一个错误,告诉他们在短时间内尝试他们所做的任何事情。对于您的服务器端基础结构,最简单的解决方案是节流。对请求的硬限制,特别是如果您可以尝试根据特定用例合理地扩展它们(例如,如果您拥有集中式服务做出一些艰难的决定,则是否要开始阻止地理位置遥远的请求,这可能导致线程挂起服务器端?还是您要平均分配不可避免但很少的中断?等)基本上可以归结为以下事实:从网关有意返回503比让请求通过并发送504便宜得多无论如何。基本上强迫客户根据您当前提供的内容行事并提供正确的响应,以便客户可以做出适当的反应。

#2 楼

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

从Google App Engine规模设计指南的在重试上实现退避部分:


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

评论


谢谢,实施退避机制是一个很好的建议,我通常会使用“瞬时故障处理应用程序块”进行可配置的指数退避。但是,通过5年以上在Azure中运行超大规模应用程序的运营经验,即使出现了指数级的退缩,“重试风暴”仍然经常发生-我一直无法找到一种可行的策略来避免它们。

–Richard Slater
17年4月15日在19:43