前言
标题应该很直观了,为了接口的稳定性还有用户体验的好感度,我们不能对所有的请求都进行有效处理并返回有效数据和结果,所以为了接口能够不崩溃、用户一直在等待或者直接报错反馈给用户,都是不好的系统反馈,所以我们使用Guava进行限制,当然,微服组件也有类似功能,这里只讲Guava
基于谷歌RateLimiter实现限流
Google的Guava工具包中就提供了一个限流工具类——RateLimiter,RateLimiter是基于“令牌通算法”来实现限流的。
代码实现
1、创建SpringBoot工程
2、添加Guava依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.2-jre</version> </dependency>
3、编写接口
@RestController public class TestController { //create(1)表示QPS=1,表示每秒生成1个令牌 private RateLimiter rateLimiter = RateLimiter.create(1); @RequestMapping("/rate-limiter") public String rateLimiter(){ //用户限流频率设置 每秒中限制1个请求,如果有令牌,也就是有请求进来,就会返回false //还有一个acquire,如果有令牌,就会直接阻塞,不推荐使用 //timeout=0,说明是非阻塞的,获取不到令牌就直接返回,不要让用户等待或者直接报错给用户 boolean tryAcquire = rateLimiter.tryAcquire(0, TimeUnit.SECONDS); if (!tryAcquire) { return "现在操作的用户过多,请稍后再试!"; } return "OK"; } }
tryAcquire()重载方法解析:
- tryAcquire() //从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
- tryAcquire(int permits) //从RateLimiter 获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话
- tryAcquire(int permits, long timeout, TimeUnit unit) //从RateLimiter 获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false (无需等待)
- tryAcquire(long timeout, TimeUnit unit) //从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)
4、测试接口
很简单,连续点击肯定会在OK和现在操作的用户过多,请稍后再试!这两个结果来回切换,如果是每隔指定时间请求接口,那就只会有OK
特点
1、RateLimiter使用令牌桶算法,会进行令牌的累积,如果获取令牌的频率比较低,则不会导致等待,直接获取令牌
2、RateLimiter由于会累积令牌,所以可以应对突发流量,也就是说如果同时请求5个令牌,由于此时令牌桶有累积的令牌,能够快速响应请求
3、RateLimiter在没有足够的令牌发放时,采用的是滞后的方式进行处理,也就是前一个请求获取令牌所需要等待的时间由下一次请求来承受和弥补,也就是代替前一个请求进行等待
总结
RateLiniter是线程安全的,并且内部存在同步锁机制,每个资源使用各自的RateLimiter,互相隔离,所以占用的内存也不会太大,而且还没有额外的线程,高能低耗,所以是轻量级的,还是比较不错的限流组件