「java常用的限流算法」java实现限流

博主:adminadmin 2022-11-26 09:13:09 60

今天给各位分享java常用的限流算法的知识,其中也会对java实现限流进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

单机限流 - 限流算法及隔离策略

计数器是一种比较简单的限流算法,用途比较广泛,在接口层面,很多地方使用这种方式限流。在一段时间内,进行计数,与阀值进行比较,到了时间临界点,将计数器清0。

线程池用来控制实际工作的线程数量,通过线程复用的方式来减小内存开销。

线程池可同时工作的线程数量是一定的,超过该数量的线程需进入线程队列等待,直至有可用的工作线程来执行任务。

信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,通过构造器指定许可的数量,每次线程执行操作时先通过acquire方法获得许可,执行完毕再通过release方法释放许可。

如果无可用许可,那么acquire方法将一直阻塞,直到其它线程释放许可。

如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

java限流原理

Google的guava包中已有相关的限流解决方案(令牌桶算法)

基于redis的限流算法可以去参考redis-cell

云南java课程分享分布式限流的运行原理

分布式编程架构技术我们在前几期的文章中已经给大家简单分析过很多次了,今天我们就一起来了解一下API网关分布式限流的运行原理都有哪些。

API网关中针对一个API、API分组、接入应用APPID,IP等进行限流。这些限流条件都将会产生一个限流使用的key,在后续的限流中都是对这个key进行限流。

限流算法通常在API网关中可以采用令牌桶算法实现。

必须说明一点的是分布式限流由于有网络的开销,TPS的支持隔本地限流是有差距的,因此在对于TPS要求很高的场景,建议采用本地限流进行处理。

下面讨论我们应该采用redis的哪一种分布式锁的方案:

由于redis事务要得到锁的效果需要在高TPS时会产生大量的无效的访问请求,所以不建议在这种场景下使用。

SETNX/EX的锁方案会产生在过期时间的问题,同时也有异步复制master数据到slave的问题。相比lua方案会产生更多的不稳定性。

我建议采用lua的方案来实施分布式锁,因为都是单进程单线程的执行,因此在TPS上和二种方案没有大的区别,而且由于只是一个lua脚本在执行,甚至是可能纯lua执行可能会有更高的TPS。当然是lua脚本中可能还是会去设置过期时间,但是应用server宕机并不会影响到redis中的锁。当然master异步复制的问题还是有,但是并不会造成问题,因为数据只会有1个lua脚本执行问题,下一个执行就正常了。

在实现方案的时候使用了Jedis库,云南java课程认为有一些问题在方案的实现层面我已经去做过验证了,可能也会是读者的疑问。

Spring Cloud Gateway 之限流操作

高并发系统常用三板斧来保护系统: 缓存 、 降级 和 限流 ,API网关作为所有请求的入口,请求量大,可以通过对并发访问的请求进行限速来保护系统的可用性。

常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等,在Zuul中我们可以自己去实现限流的功能,Spring Cloud Gateway的出现本身就是用来替代Zuul的,要想替代那肯定得有强大的功能,除了性能上的优势之外,Spring Cloud Gateway还提供了很多新功能,比如限流操作,使用起来非常简单。

目前限流提供了基于Redis的实现,首先引入依赖,

然后就可以以通过KeyResolver来指定限流的Key,比如我们需要根据用户来做限流,IP来做限流等等。

通过exchange对象可以获取到请求信息,这边用了HostName。

通过exchange对象可以获取到请求信息,获取当前请求的用户ID或者用户名,使用这种方式限流,请求路径中必须携带userId参数。

获取请求地址的uri作为限流key。

配置好后就可以进行限流测试了,注意观察redis中的数据。

限流算法介绍

高并发的处理有三个比较常用的手段,缓存,限流和降级。缓存的使用相信很多开发者都很了解了,诸如redis,memcache等工具都会活跃在我们的系统当中。但是假如在某一时间段内出现了远超预想的流量访问到系统,例如在搞秒杀活动之类的,这样一来我们应该如何保护业务系统呢?

在参加一些秒杀活动的时候,我们可以看到,有时候会有 系统繁忙,请稍后再试

或者 请稍等 的提示,那这个系统就很可能是使用了限流的手段。

限流是限制系统的输入和输出流量,以达到保护系统的目的。而限流的实现主要是依靠限流算法,限流算法主要有4种:

1、固定时间窗口(计数器);

2、滑动时间窗口;

3、令牌桶算法;

4、漏桶算法;

计数器就是统计记录单位时间内进入系统或者某一接口的请求次数,在限定的次数内的请求则正常接收处理,超过次数的请求则拒绝掉,或者改为异步处理。

假设我们设定单位时间内进入系统的的最大请求数为100,如果有超过100个请求集中在刷新计数器的临界点前后进入系统,而且单位时间的粒度比较粗的话,那就容易误伤很多正常请求。

这个名称要跟TCP的窗口滑动区分开来,但是理解之后会发现其实也是有点相似。

计数器算法对流量的限制比较粗放,而滑动时间窗口的算法则是对流量进行更加平稳的控制。上面的计数器的单位时间是1分钟,而在使用滑动时间窗口,可以把1分钟分成6格,每格时间长度是10s,每一格又各自管理一个计数器,单位时间用一个长度为60s的窗口描述。一个请求进入系统,对应的时间格子的计数器便会+1,而每过10s,这个窗口便会向右滑动一格。只要窗口包括的所有格子的计数器总和超过限流上限,便会拒绝后面的请求。

漏桶算法,又称leaky bucket。下图是wiki上的漏桶图解:

一个系统处理请求,就像一个固定容量的水桶去溜进来的水,同时也让水流出去,但是它无法预见有多少水流进来和水流进来的速度,它只能够控制从桶底水流出去的速度,多出来的水,就只好让它从桶边流出去了。这个从桶底流出去的水就是系统正常处理的请求,从旁边流出去的水就是系统拒绝掉的请求。如此一来,我们只要监控系统单位时间内处理请求的速率就可以了,速率超过上限后的请求都给拒绝掉就可以了。

继续wiki图解。

令牌桶即是以一定速率生成token并放入桶中,请求进入系统需要先拿到token才能进行业务处理,无token的请求则拒绝掉。令牌桶算法实际上跟漏桶算法很相似,而实际使用中其实也不需要另起线程生成token,只需要把握好token生成速率和当前应该剩余的token数量即可。

在时间点刷新的临界点上,只要剩余token足够,令牌桶算法会允许对应数量的请求通过,而后刷新时间因为token不足,流量也会被限制在外,这样就比较好的控制了瞬时流量。因此,令牌桶算法也被广泛使用。

四种限流算法原理

限流这里总结了四个算法分别是 计数器固定窗口算法、计数器滑动窗口算法、漏斗算法、令牌桶算法

计数器固定窗口算法是最基础也是最简单的一种限流算法。原理就是对一段固定时间窗口内的请求进行计数,如果请求数超过了阈值,则舍弃该请求;

如果没有达到设定的阈值,则接受该请求,且计数加1。当时间窗口结束时,重置计数器为0。

优点:实现简单容易理解

缺点: 流量曲线可能不够平滑,有"突刺现象"

计数器滑动窗口算法是计数器固定窗口算法的改进,解决了固定窗口切换时可能会产生两倍于阈值流量请求的缺点

滑动窗口算法在固定窗口的基础上,将一个计时窗口分成了若干个小窗口,然后每个小窗口维护一个独立的计数器,当请求的时间大于当前窗口的最大时间时,则将计时窗口向前平移一个小窗口。

平移时,将第一个小窗口的数据丢弃,然后将第二个小窗口设置为第一个小窗口,同时在最后新增一个小窗口,将新的请求放在新增的小窗口中。同时要保证整个窗口中所有小窗口的请求数目之后不能超过设定的阈值。

滑动窗口其实就是固定窗口的升级版。将计时窗口划分成一个小窗口,滑动窗口算法就退化成了固定窗口算法。而滑动窗口算法其实就是对请求数进行了更细粒度的限流。

窗口划分的越多,则限流越精准

请求来了之后会首先进到漏斗里,然后漏斗以恒定的速率将请求流出进行处理,从而起到平滑流量的作用。当请求的流量过大时,漏斗达到最大容量时会溢出,此时请求被丢弃。

从系统的角度来看,我们不知道什么时候会有请求来,也不知道请求会以多大的速率来,这就给系统的安全性埋下隐患。但是如果加了一层漏斗算法限流之后,就能够保证请求以恒定的速率流出。

在系统看来,请求永远是以平滑的传输速率过来,从而起到来保护系统的作用。

漏斗特点:

令牌桶算法是对漏桶算法的一种改进,除了能够在限制调用的平均速率的同时还允许一定程度的流量突发。

计数器固定窗口算法实现简单,容易理解。和漏斗算法相比,新来的请求也能够被马上处理到。但是流量曲线可能不够平滑,有"突刺现象",在窗口切换时可能会产生两倍于阈值流量的请求。

而计数器滑动窗口算法作为计数器固定窗口算法的一种改进,有效解决了窗口切换时可能会产生两倍于阈值流量请求的问题

漏斗算法能够对流量起到整流的作用,让随机不稳定的流量以固定的速率流出,但是不能解决流量突发的问题。

令牌桶算法作为漏斗算法的一种改进,除了能够起到平滑流量的作用,还允许一定程度的流量突发。

没有最好的算法,只有最合适的算法

比如令牌桶算法一般用于保护自身的系统,对调用者进行限流,保护自身的系统不被突发的流量打垮。如果自身的系统实际的处理能里强于配置的流量限制时,可以允许一定程度的流量突发,使得实际的处理速率,充分利用系统资源。

而漏斗算法一般用于保护第三方的系统,比如自身的系统需要调用第三方的接口,为了保护第三方的系统不被自身的调用打垮,便可以通过漏斗算法进行限流,保证自身的流量平稳的达到第三方的接口上。

算法是死的,场景是活的。没有最好的,只有最合适的。

关于java常用的限流算法和java实现限流的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

发布于:2022-11-26,除非注明,否则均为首码项目网原创文章,转载请注明出处。