[译] 负载性能

Netflix 的自适应并发限制前端

Eran Landau、William Thurston、Tim Bozarth 做android

在 Netflix,咱们沉迷于服务可用性的研究,关于如何实现目标这几年也写了几篇博客文章。这些技术包括了断路器模式、并发限制、混沌测试等等。如今咱们宣布最近的创新:自适应并发限制。自适应并发限制从根本上提高了应用程序在极端负载下的表现,并使得咱们能够避免级联服务故障。咱们移除了断定系统并发限制的艰难工做,又保证了延迟保持较低水平。本文发布的同时,咱们开源了一个简单的 Java 类库,集成了 servlet、executor 和 GRPC 框架支持。ios

简要的背景介绍

并发量其实就是系统在任意时刻可以处理的请求数,一般是由硬件资源决定的,好比 CPU。一般咱们使用利特尔法则(Little’s Law)计算系统的并发量:稳定状态下的系统,并发量等于平均服务时间与平均服务速率的乘积(L = 𝛌W)。任何超过该并发量的请求都不能当即获得服务,必须排队或被拒绝。如此说来,即使请求到达速率和服务时间都不均匀,作些排队处理就能令整个系统被充分利用起来,所以它是很必要的。git

当队列没有强制限制时系统会出问题,好比在很长的时间内请求到达速度都超过请求结束速度。随着队列增加,延迟也增加了,直到全部的请求都开始超时,最终系统耗尽内存而后崩溃。若是留下未经检测的延迟,它就会对其调用者产生不利影响,从而致使系统的级联故障。github

强制进行并发限制不是什么新奇玩意儿;难的是在大型的动态分布式系统中找到并发量限制,并且这个系统的并发量和延迟特征还在不断改变。咱们解决方案给出的主要目的,就是动态地肯定并发量限制。这一并发量能够被视为在系统性能降低前(如延迟)所容许的最大请求数量(实时并发量+排队中的请求)。算法

解决方案

之前,在 Netflix 咱们手动配置了由复杂的性能测试和分析获得的并发限制。虽然这在某一时刻很准确,可是一旦系统部分停运致使拓扑结构变化、系统自动扩展(auto scaling)或是推送代码上线引发延迟特征变化,这一测量值都会很快过期。后端

咱们知道咱们能够作得比静态的并发限制更好,因此咱们探索了自动肯定系统固有并发限制的方案,该方案:bash

1. 不须要人工

2. 不须要集中协调

3. 不须要硬件信息或系统拓扑结构就能肯定并发限制

4. 能适应系统的拓扑结构变更

5. 计算容易,执行简单
复制代码

为了解决该问题,咱们转向尝试真正的 TCP 拥塞控制算法,不会引发超时或增长延迟就能探明能够同时传输多少个数据包(好比拥塞窗口大小)。这些算法持续跟踪各类指标,以估算系统的并发限制,并持续调节拥塞窗口大小。服务器

咱们能够看到这个系统用蓝线表明了未知的实际并发量。客户端起初发送的请求被限制在较低的并发水平,系统在延迟不增长的状况下经过增长并发窗口频繁探测更高的并发量。当延迟真的开始增加时,传感器假定到达了并发极限,降回拥塞窗口大小。并发限制的探测持续进行,就产生了上图的锯齿状图像。并发

咱们的算法创建在基于延迟的 TCP 拥塞控制算法的基础上,该算法查看最小的延迟(表明没有排队的最佳状况)除以按时间进行采样测量的延迟之间的比率,做为识别队列产生并开始致使延迟增长的衡量参照。从该比值能够获知延迟变化的梯度或级别:gradient=(RTTnoload/RTTactual) (译者注:RTT 指 TCP 链接中一个数据包的往返时间,RTTnoload 指没有延迟的最小 RTT 值,RTTactual 指实际的 RTT 值)。值为 1 表示没有出现排队,能够增大并发限制;小于 1 的值表示造成了过多队列,应该减小并发限制。对于每一个新样本,利用此比率调整并发限制,并使用一个简单公式增长所容许的队列大小:

newLimit = currentLimit × gradient + queueSize
复制代码

通过几回迭代后,算法收敛到某个保持延迟较低的并发限制水平,同时容许一些排队处理来处理突发请求。所容许的队列大小是可调整的,而且该值决定了并发限制的增加速度。咱们认定当前并发限制的算术平方根是个不错的默认值。选择算数平方根,主要是由于它能很大程度上反映出当前并发限制在较低请求数时的有用特性,容许迭代时快速增加,而在出现大量请求时又能灵活减少,从而保证了系统稳定。

启用自适应并发限制

启用后,自适应服务器端并发限制会拒绝过多的 RPS(Request Per Second) 来保持较低的延迟,从而保护实例自身及其所依赖的服务。若是不拒绝过多的并发请求,RPS 或者延迟的持续增长都会转化为更糟糕的延迟并最终致使系统故障。服务如今可以减小过多的负载并保持较低的延迟,而其余缓和措施(如自动扩展)则会起做用。

注意这一点很重要:在服务器层面强制执行并发限制(不进行协调),每一个服务器的流量限制可能应用得至关迅速。 所以,获得的并发请求限制和数量在不一样服务器间可能相差较大,从云服务商租用的多个服务器尤为如此。 当其余地方有足够的承载能力时,可能引发某台服务器脱离服务集群。话虽如此,使用了客户端侧负载均衡,客户端只需重试一次请求,几乎就能 100% 到达一台可用的服务实例。更棒的是,因为服务可以在亚毫秒时间内极速减小流量,这对服务性能的影响微乎其微,所以不用再担忧客户端重试请求引发的 DDOS 和重试风暴(译者注:应该是指大量客户端由于请求被拒绝而反复重试服务请求)。

总结

随着咱们推出自适应的并发限制,咱们再也不须要像看小孩同样看着系统性能,而后手动调整服务负载。 更重要的是,它同时提升了咱们整个基于微服务的生态系统的可靠性和可用性。

咱们很高兴在一个小型开源库中分享咱们的思路实现和常见框架集成:http://github.com/Netflix/concurrency-limits。 咱们但愿,任何想要保护其服务免于级联故障和与负载引发的延迟降级的人,均可以利用咱们的代码来实现更好的可用性。 咱们期待社区的反馈,并乐意接受新算法或框架集成的 Pull Request。

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索