流量预警和限流方案中,比较常用的有两种。第一种滑窗模式,通过统计多个单元时间的访问次数来进行控制,当单位时间的访问次数达到的某个峰值时进行限流。第二种为响应模式,通过控制当前活跃请求数,来进行流量控制。下面来简单分析下两种的优缺点。
1、滑窗模式
模式分析:
在每次有访问进来时,我们判断前N个单位时间里总访问量是否超过了设置的阈值,若超过则不允许执行。
这种模式的实现的方式更加契合流控的本质意义。理解较为简单。但由于访问量的预先不可预见性,会发生单位时间的前半段有大量的请求涌入,而后半段则拒绝所有请求的情况发生。(一般,需要会将单位时间切的足够的细来解决这个问题)其次,我们很难确定这个阈值设置在多少比较合适,只能通过经验或者模拟(如压测)来进行估计,不过即使是压测也很难估计的准确,线上每台机器的硬件参数的不同,或者同一台机子在不同的时间点其可以接受的阈值也不尽相同(系统中),每个时间点导致能够承受的最大阈值也不尽相同,我们无法考虑的周全。
所以滑窗模式往往用来对某一资源的保护上(或者说是承诺比较合适:我对某一接口的提供者承诺过,最高调用量不超过XX),如对db的保护,对某一服务的调用的控制上。因为对于我们应用来说,db或某一接口就是一共单一的整体。
代码实现思路:
每一个窗(单位时间)就是一个独立的计数器(原子计数器),用以数组保存。将当前时间以某种方式(比如取模)映射到数组的一项中。每次访问先对当前窗内计数器+1,再计算前N个单元格的访问量综合,超过阈值则限流。
这里有个问题,时间永远是递增的,单纯的取模,会导致数组过长,使用内存过多,我们可以用环形队列来解决这个问题。
2、响应模式
模式分析:
每次操作执行时,我们通过判断当前正在执行的访问数是否超过某个阈值在决定是否限流。
该模式看着思路比较的另类,但却有其独到之处。实际上我们限流的根本是为了保护资源,防止系统接受的请求过多,应接不暇,拖慢系统中其他接口的服务,造成雪崩。也就是说我们真正需要关心的是那些运行中的请求,而那些已经完成的请求已是过去时,不再是需要关心的了。
我们来看看其阈值的计算方式,对于一个请求来说,响应时间rt/qps是一个比较容易获取的参数,那么我们这样计算:qps/1000*rt。
此外,一个应用往往是个复杂的系统,提供的服务或者暴露的请求、资源不止一个。内部GC、定时任务的执行、其他服务访问的骤增,外部依赖方、db的抖动,抑或是代码中不经意间的一个bug。都可能导致相应时间的变化,导致系统同时可以执行请求的变化。而这种模式,则能恰如其分的自动做出调整,当系统不适时,rt增加时,会自动的对qps做出适应。
代码实现思路:
当访问开始时,我们对当前计数器(原子计数器)+1,当完成时,-1。该计数器即为当前正在执行的请求数。只需判断这个计数器是否超过阈值即可。