上一篇:深夜看了张一鸣的微博,让我越想越后怕

作者:fredalxin
地址:https://fredal.xin/netflix-concuurency-limits

作为应对高并发的手段之一,限流并不是一个新鲜的话题了。从Guava的Ratelimiter到Hystrix,以及Sentinel都可作为限流的工具。

自适应限流

一般的限流常常需要指定一个固定值(qps)作为限流开关的阈值,这个值一是靠经验判断,二是靠通过大量的测试数据得出。但这个阈值,在流量激增、系统自动伸缩或者某某commit了一段有毒代码后就有可能变得不那么合适了。并且一般业务方也不太能够正确评估自己的容量,去设置一个合适的限流阈值。

而此时自适应限流就是解决这样的问题的,限流阈值不需要手动指定,也不需要去预估系统的容量,并且阈值能够随着系统相关指标变化而变化。

自适应限流算法借鉴了TCP拥塞算法,根据各种指标预估限流的阈值,并且不断调整。大致获得的效果如下:

从图上可以看到,首先以一个降低的初始并发值发送请求,同时通过增大限流窗口来探测系统更高的并发性。而一旦延迟增加到一定程度了,又会退回到较小的限流窗口。循环往复持续探测并发极限,从而产生类似锯齿状的时间关系函数。

TCP Vegas

vegas是一种主动调整cwnd的拥塞控制算法,主要是设置两个阈值alpha 和 beta,然后通过计算目标速率和实际速率的差diff,再比较差diff与alpha和beta的关系,对cwnd进行调节。伪代码如下:

diff = cwnd*(1-baseRTT/RTT)
if (diff < alpha)
set: cwnd = cwnd + 1
else if (diff >= beta)
set: cwnd = cwnd - 1
else
set: cwnd = cwnd

其中baseRTT指的是测量的最小往返时间,RTT指的是当前测量的往返时间,cwnd指的是当前的TCP窗口大小。通常在tcp中alpha会被设置成2-3,beta会被设置成4-6。这样子,cwnd就保持在了一个平衡的状态。

netflix-concuurency-limits

concuurency-limits是netflix推出的自适应限流组件,借鉴了TCP相关拥塞控制算法,主要是根据请求延时,及其直接影响到的排队长度来进行限流窗口的动态调整。

alpha , beta & threshold

vegas算法实现在了VegasLimit类中。先看一下初始化相关代码:

private int initialLimit = 20;
private int maxConcurrency = 1000;
private MetricRegistry registry = EmptyMetricRegistry.INSTANCE;
private double smoothing = 1.0;private Function<Integer, Integer> alphaFunc = (limit) -> 3 * LOG10.apply(limit.intValue());
private Function<Integer, Integer> betaFunc = (limit) -> 6 * LOG10.apply(limit.intValue());
private Function<Integer, Integer> thresholdFunc = (limit) -> LOG10.apply(limit.intValue());
private Function<Double, Double> increaseFunc = (limit) -> limit + LOG10.apply(limit.intValue());
private Function<Double, Double> decreaseFunc = (limit) -> limit - LOG10.apply(limit.intValue());

这里首先定义了一个初始化值initialLimit为20,以及极大值maxConcurrency1000。其次是三个 阈值函数alphaFunc,betaFunc以及thresholdFunc。最后是两个增减函数increaseFunc和decreaseFunc。函数都是基于当前的并发值limit做运算的。

  1. alphaFunc可类比vegas算法中的alpha,此处的实现是3*log limit。limit值从初始20增加到极大1000时候,相应的alpha从3.9增加到了9。

  2. betaFunc则可类比为vegas算法中的beta,此处的实现是6*log limit。limit值从初始20增加到极大1000时候,相应的alpha从7.8增加到了18。

  3. thresholdFunc算是新增的一个函数,表示一个较为初始的阈值,小于这个值的时候limit会采取激进一些的增量算法。这里的实现是1倍的log limit。mit值从初始20增加到极大1000时候,相应的alpha从1.3增加到了3。

这三个函数值可以认为确定了动态调整函数的四个区间范围。当变量queueSize = limit × (1 − RTTnoLoad/RTTactual)落到这四个区间的时候应用不同的调整函数。

变量queueSize

其中变量为queueSize,计算方法即为limit × (1 − RTTnoLoad/RTTactual),为什么这么计算其实稍加领悟一下即可。

我们把系统处理请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处理顺畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的,即RTTnoLoad;

反之,当请求堆积的时候,那么处理请求的时间则会变为:排队时间+最短处理时间,即RTTactual = inQueueTime + RTTnoLoad。而显然排队的队列长度为 总排队时间/每个请求的处理时间及queueSize = (limit * inQueueTime) / (inQueueTime + RTTnoLoad) = limit × (1 − RTTnoLoad/RTTactual)

再举个栗子,因为假设当前延时即为最佳延时,那么自然是不用排队的,即queueSize=0。而假设当前延时为最佳延时的一倍的时候,可以认为处理能力折半,100个流量进来会有一半即50个请求在排队,及queueSize= 100 * (1 − 1/2)=50

动态调整函数

调整函数中最重要的即增函数与减函数。从初始化的代码中得知,增函数increaseFunc实现为limit+log limit,减函数decreaseFunc实现为limit-log limit,相对来说增减都是比较保守的。

看一下应用动态调整函数的相关代码:

private int updateEstimatedLimit(long rtt, int inflight, boolean didDrop) {final int queueSize = (int) Math.ceil(estimatedLimit * (1 - (double)rtt_noload / rtt));double newLimit;// Treat any drop (i.e timeout) as needing to reduce the limit// 发现错误直接应用减函数decreaseFuncif (didDrop) {newLimit = decreaseFunc.apply(estimatedLimit);// Prevent upward drift if not close to the limit} else if (inflight * 2 < estimatedLimit) {return (int)estimatedLimit;} else {int alpha = alphaFunc.apply((int)estimatedLimit);int beta = betaFunc.apply((int)estimatedLimit);int threshold = this.thresholdFunc.apply((int)estimatedLimit);// Aggressive increase when no queuingif (queueSize <= threshold) {newLimit = estimatedLimit + beta;// Increase the limit if queue is still manageable} else if (queueSize < alpha) {newLimit = increaseFunc.apply(estimatedLimit);// Detecting latency so decrease} else if (queueSize > beta) {newLimit = decreaseFunc.apply(estimatedLimit);// We're within he sweet spot so nothing to do} else {return (int)estimatedLimit;}}newLimit = Math.max(1, Math.min(maxLimit, newLimit));newLimit = (1 - smoothing) * estimatedLimit + smoothing * newLimit;if ((int)newLimit != (int)estimatedLimit && LOG.isDebugEnabled()) {LOG.debug("New limit={} minRtt={} ms winRtt={} ms queueSize={}",(int)newLimit,TimeUnit.NANOSECONDS.toMicros(rtt_noload) / 1000.0,TimeUnit.NANOSECONDS.toMicros(rtt) / 1000.0,queueSize);}estimatedLimit = newLimit;return (int)estimatedLimit;
}

动态调整函数规则如下:

  1. 当变量queueSize < threshold时,选取较激进的增量函数,newLimit = limit+beta

  2. 当变量queueSize < alpha时,需要增大限流窗口,选择增函数increaseFunc,即newLimit = limit + log limit

  3. 当变量queueSize处于alpha,beta之间时候,limit不变

  4. 当变量queueSize大于beta时候,需要收拢限流窗口,选择减函数decreaseFunc,即newLimit = limit - log limit

平滑递减 smoothingDecrease

注意到可以设置变量smoothing,这里初始值为1,表示平滑递减不起作用。

如果有需要的话可以按需设置,比如设置smoothing为0.5时候,那么效果就是采用减函数decreaseFunc时候效果减半,实现方式为newLimitAfterSmoothing = 0.5 newLimit + 0.5 limit

感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

· END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

正文结束

推荐阅读 ↓↓↓

1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

2.如何才能成为优秀的架构师?

3.从零开始搭建创业公司后台技术栈

4.程序员一般可以从什么平台接私活?

5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6.IntelliJ IDEA 2019.3 首个最新访问版本发布,新特性抢先看

7.漫画:程序员相亲图鉴,笑屎我了~

8.15张图看懂瞎忙和高效的区别!

一个人学习、工作很迷茫?

点击「阅读原文」加入我们的小圈子!

常用的限流框架都在这里了!相关推荐

  1. 常用的限流框架,你都会用吗?

     作者:fredal fredal.xin/netflix-concuurency-limits 作为应对高并发的手段之一,限流并不是一个新鲜的话题了.从Guava的Ratelimiter到Hystr ...

  2. 亿级流量治理系列:常用的限流算法有哪些?

    前言 上篇文章<为什么大公司都要做流量治理?>跟大家聊了下做流量治理的真正目的是什么.如果你要开发一个流量治理的平台或者一个限流的框架,那么必不可少的就是要选择一种合适的限流算法.本篇文章 ...

  3. 项目分享-限流框架的实现

    背景 开篇之前我一直在想怎么把这个项目给讲清楚,如果在互联网公司有高并发场景对于这个内容的就比较容易接受.这里大概说一下背景:代码写于2013年四月份,最开始的雏形是在2012年写的,从另外一个项目上 ...

  4. 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架

    Dnc.Api.Throttle    适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...

  5. 介绍一个基于Spring Redis Lua的无侵入应用级网关限流框架

    介绍一个基于Spring Redis Lua的无侵入应用级网关限流框架 项目介绍 为什么选择spring-redis-current-limit Quick Start 1. 引入spring-red ...

  6. 【限流02】限流算法实战篇 - 手撸一个单机版Http接口通用限流框架

    本文将从需求的背景.需求分析.框架设计.框架实现几个层面一步一步去实现一个单机版的Http接口通用限流框架. 一.限流框架分析 1.需求背景 微服务系统中,我们开发的接口可能会提供给很多不同的系统去调 ...

  7. WebApiThrottle限流框架

    一.WebApiThrottle限流框架 1.Nuget安装(PM) PM> Install-Package WebApiThrottle WebApiThrottle支持自定义配置各种限流策略 ...

  8. 阿里开源分布式限流框架 -Sentinel Go 0.3.0 发布,支持熔断降级能力

    作者 | 宿何  阿里巴巴高级开发工程师 Sentinel 是阿里巴巴开源的,面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统自适应保护等多个维度来帮助开发者保障 ...

  9. java服务端限流框架,美团大众点评服务框架Pigeon

    服务框架Pigeon架构 ? Pigeon提供jar包接入 ,线上运行在tomcat里 ? Monitor-CAT ,负责调用链路分析.异常监控告警等 ? 配置中心-Lion ,负责一些开关配置读取 ...

  10. 微服务中常用的限流算法(一)

    一个业务系统在指定配置的服务器上,可以承载的容量是一定的,当请求流量超过系统的容量后,系统就会变得不稳定,可用性下降,为了保证系统的可用性,需要将系统能够承载容量之外的流量进行丢弃,这样虽然会导致部分 ...

最新文章

  1. Qt 学习之路:模型-视图高级技术
  2. 我可以强制pip重新安装当前版本吗?
  3. 多线程中数据的并发访问与保护
  4. python封装类在当前文件中使用_name_下调用不了_学python中对于类怎么也不明白,对了是看到简明教程11章,类与变量的对象....想要通俗易懂的答案....
  5. 初等数论--整除--公倍数一定是最小公倍数的倍数
  6. excel实战应用案例100讲(四)-Excel玩转数据:从分析到可视化
  7. j计算机实验室安全操作规范,实验室安全操作规程
  8. Swift编码总结8
  9. 2021年最值得推荐的七款可视化工具,人人都能学会使用
  10. MSSQL同步刷新视图字段长度和源表保持一致
  11. 网络无人自动安装centos 6.2 + PXE + httpd + kickstart
  12. C# 利用NPOI 实现Excel转html
  13. Proxmark3教程1:用PM3解密复制M1全加密门禁IC卡图文详细介绍
  14. linux下好看的中文字体,推荐一款 Linux 上比较漂亮的字体(转)
  15. 交换机和路由器的区别_一文读懂交换机和路由器的区别
  16. blowfish java_blowfish加密算法
  17. Unity实现可调子屏幕(类小地图)效果
  18. canvas制作圆角矩形(包括填充矩形的功能)
  19. 三级等保 关闭111端口
  20. java数组初始化的方式,java中初始化数组的方式有几种

热门文章

  1. iOS 单个页面设置横屏
  2. 和 Pipelining 说再见,cURL 放弃使用管道技术
  3. 函数对象、对象、原型
  4. python - 多线程、装饰器
  5. 谁有能锁屏不崩溃的录屏软件给推荐个。。。。
  6. 搭建Yum服务器及编译安装Httpd实验
  7. c# 第8节 变量、变量名命令规则、作用域、@的作用
  8. 《C Primer Plus》读书笔记
  9. SVN创建项目以及检出项目
  10. 如何防止 Safari 使用来自 iOS 15 和 macOS Monterey 的网站着色?