网络超时检测的三种方法(当你的网站面临崩溃)

大家好,今天跟大家聊聊后台的限流技术,如有不对,欢迎指正哦!

什么是限流

我们先来看看维基百科的定义:

网络超时检测的三种方法(当你的网站面临崩溃)(1)

通俗点讲,限流就是流量限制,可以用来管控请求的速度。那为什么需要管控请求速度呢?来看以下一个场景:

自己开发过一个网站,为了方便存储网站的数据,买了一个四核的数据库,算下来网站每秒能处理的请求也就几千量级。如果这时候网站访问过于火爆,涌进来一波流量,这波流量以每秒10w的频率访问业务,然后直接打到数据库,那么数据库可能会不堪重负,直接被压垮了。

网络超时检测的三种方法(当你的网站面临崩溃)(2)

所以不管是什么后台服务,每秒能处理的请求个数总有极限。如果超过这个极限,轻则让服务变得缓慢,重则直接干跨业务,因此我们需要使用一些手段限制请求的发送频率。一般来说,我们可以限制总的频率,也可以更精细一点,比如针对用户、IP等维度进行配额分发,思路都是相同的。

下面,就来给大家介绍下几种不同的限频算法,他们各有特色和优点,掌握他们就可以应对各个不同的场景。

计数器算法

顾名思义,计数器算法就是通过计数来记录请求次数。先设定一个阈值,要求单位时间内的请求不得超过这个阈值。比如我们把单位时间内的阈值定为1000,每来一个请求,就计数 1,达到1000就拒绝访问。等到过了单位时间,再重新计数。

在具体实现中,如果是单机限流,可以用一个整数 时间戳记录。时间戳达到上限,则从0开始,计数达到阈值则拒绝。

分布式限流的话,一般使用Redis来做,可以利用 Redis 天然的过期时间,到了设定时间就自动过期。同时,记得要使用 LUA 脚本来保证 redis 的原子操作。

网络超时检测的三种方法(当你的网站面临崩溃)(3)

计数器算法的优点在于实现简单,不易出错。缺点:有请求突刺,可能会超过我们单位时间的阈值

比如我们希望一段时间的请求数最多是2000,时间窗口是t1开始,到t2结束,然后是t2开始,到t3结束,那先在t2前一瞬间发送1000的请求,t2后一瞬间又立即发1000个请求,那么在t1-t2,t2-t3这两个时间窗口中,虽然都满足了每分钟不超过1000这个规则,但实际上在t2前后,这一分钟的请求已达2000。

网络超时检测的三种方法(当你的网站面临崩溃)(4)

滑动窗口算法

滑动窗口算法,实际是计数器算法的优化版本。

计数器算法上面所说的突刺问题,本质是什么?是我们将一段时间看成一个整体,而不是以基于物理时间来看时间窗口,这就导致有漏洞可循。

那么对症下药,我们以当前物理时间为基点往前看,看基于当前时间的时间窗口,是否超过阈值,超过阈值就拒绝请求,问题就迎刃而解了。

我们相当于是将一个时间窗口,分为多个格子,比如20s一个格子,那我们一分钟的时间窗口,就被分为了三个格子。每次基于当前时间,往前看三个格子,就是当前的滑动请求量。

有点抽象是不是,以时间粒度1小时举个例子:

如果是普通窗口,时间区间就是1:00-2:00, 2:00-3:00这样。如果有人在2:00前后搞事情,那就会造成突刺,突破上限。

而滑动窗口始终是基于当前,如果现在是2:00,那窗口就是1:00-2:00,如果是2:15,窗口就是1:15-2:15。

如果你在2点前几乎怼满了一波,那你必须得等当前时间滑得够远,你才怼第二波,这就解决了突刺。

网络超时检测的三种方法(当你的网站面临崩溃)(5)

说到这里,大家可能要提一个问题,是不是计数器算法足够小,也能解决突刺的问题?既然如此,滑动窗口还有意义么?

其实仔细想一下,滑动的本质是基于当前的物理时间看窗口请求量,足够小只是粒度问题,滑动窗口同样可以把粒度调小,但无论多小,滑动窗口都可以解决计数器算法解决不了的突刺超额问题。

小羊认为,滑动窗口就是计数器的完善版本。而计数器算法在突刺情况下,并没有满足 “单位时间内的请求数量不超过某个值” 的需求。

而从复杂度来讲,滑动窗口虽说比技术器难一些,但也就100步和50步,一个量级。所以,如果实际开发中在计数器和滑动窗口上选型,那么不用犹豫,选滑动窗口吧。

漏桶算法

前面介绍的是计数类算法,下面开始给大家介绍 Traffic Shaping 类的解决方式,我们先来看漏桶算法:

我们有一个桶,入水速度不定,出水速度由于管口较小,都是一滴一滴下来,所以速度恒定。如果桶满了,我们就不能再往里面加水了。

可以看到,入口流量频率不变,出口速率始终恒定,我们利用这个特性,就可以做到均匀限频。

网络超时检测的三种方法(当你的网站面临崩溃)(6)

但是漏桶算法也有一个明显的缺点,我们无法精确判断网络带宽或处理能力。一般来说都只能设置一个相对比较小的流量目标,比如800/s。如果产生了一波突发流量,经过了漏桶算法后,依然会以恒定的目标码率慢慢地发送。就算我们的服务有足够的实力,也不能让它快速处理了。所以说,漏桶算法无法充分用满性能资源。

那怎么解决呢?有两种方式:

  1. 动态调节水滴速度(就像输液瓶一样):通过对后端进行不断试探,尽可能始终维持在性能处理的极致,这种方式的弊端在于带来了更多的复杂性和耦合性,属于特定优化了。

2. 用另一种桶,令牌桶。

令牌桶算法

令牌桶算法是这样的:我们有一个桶,桶里均匀产生令牌,如果令牌把桶塞满了,就不会再生产令牌。请求过来的时候,需要先拿到桶里的令牌,才能做后续处理,如果桶里没有令牌了,可以选择放弃或等待。

举个例子:

我们桶里面能放1000个令牌,1ms产生一个令牌,那1s就可以装满这个桶,请求要处理,先从桶里拿令牌,这样1s就能处理1000次,令牌桶算法很像生产消费模式,同时出口流量也很稳定。

令牌桶算法能够在请求量小的时候,积累令牌,这种模式在限制数据的平均传输速率的同时还允许某种程度的突发传输。

网络超时检测的三种方法(当你的网站面临崩溃)(7)

四种算法对比

大家可能会说,这么多算法,到底用哪种好的,别急,这就来比较下他们的优缺点。我们分别从复杂性、均匀度和容忍突发流量几个维度来看:

复杂性:令牌桶 >= 漏桶 > 滑动窗口 > 计数器,但实际上限流算法都不复杂,并且都有现成的实现,生产时候还是以实际需求为主,复杂性不用考虑太多。

均匀度:令牌桶和漏桶,其实都属于流量整形算法,流量整形是说指不管流量到达的速率多么不稳定,在接收流量后,都可以将其匀速输出。而滑动窗口算法,计数器算法,只是限制了一段时间的个数,没有流量整形的效率,均匀度会低一些。

容忍突发流量:指的是限流策略允许流量在短时间内突增,且在突增结束后不会影响后续流量的正常限流,这一块的话只有令牌桶支持。

复杂性

均匀度

突发流量处理

计数器

不均匀

不支持

滑动窗口

不均匀

不支持

漏桶

强均匀

不支持

令牌桶

均匀

支持

实际生产中用什么

在实际生产中,令牌桶因为其均匀性及突发流量容忍性,更受青睐。据小羊了解,腾讯云团队,阿里线上管控体系,Shopee 金融团队,都使用了令牌桶来做限流。

而唯一可以和令牌桶 battle 的漏桶,漏桶没有针对突发流量的处理,严格限制,个人感觉这不是缺陷而是特性,并不是每个场景,都需要支持突发流量的,如果要很严格限定流量,漏桶会是最好的选择。

至于计数器和滑动窗口算法,优势就是简单,但限流算法实际都不复杂,所以这个优势就很不明显了,生产上不建议使用。

限流是开发领域一个非常重要的话题,毕竟流控做好了,才不容易过载,才能有个稳定的系统,嘻嘻,希望大家看了文章有所收获呀~

原文:https://mp.weixin.qq.com/s/n09acNYqktHbS_LsCdTc8g

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页