限流
限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。常用的限流算法有令牌桶和和漏桶,而Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。
在开发高并发系统时有三把利器用来保护系统:
- 缓存:缓存的目的是提升系统访问速度和增大系统处理容量
- 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行
- 限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理
限流算法
漏桶算法
漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:
因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.
令牌桶算法
令牌桶算法原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
示意图如下:
令牌桶的好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.
令牌桶算法的使用
RateLimiter简介
Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法(Token Bucket)来完成限流,非常易于使用。RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率.它支持两种获取permits接口,一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到。
RateLimiter的使用
- maven
1
2
3
4
5<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency> - 实例
1 | public static void main(String[] args) { |
- 结果
1
2
3
4
5
6
7
8
9
10time:2019-09-03 10:08:11---------------1
time:2019-09-03 10:08:12---------------2
time:2019-09-03 10:08:13---------------3
time:2019-09-03 10:08:14---------------4
time:2019-09-03 10:08:15---------------5
time:2019-09-03 10:08:16---------------6
time:2019-09-03 10:08:17---------------7
time:2019-09-03 10:08:18---------------8
time:2019-09-03 10:08:19---------------9
time:2019-09-03 10:08:20---------------10实际使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GuavaRateLimiterService {
/**
* 每秒控制5个许可
*/
RateLimiter rateLimiter = RateLimiter.create(5.0);
/**
* 获取令牌
*
* @return
*/
public boolean tryAcquire() {
return rateLimiter.tryAcquire();
}
}亦可用自定义注解+切面的方式实现1
2
3
4
5
6
7
8
9
10
11
12
private GuavaRateLimiterService guavaRateLimiterService;
public String sayHello() {
if (guavaRateLimiterService.tryAcquire()) {
log.info("获取许可成功");
return "hello";
}
log.info("获取许可失败");
return "hi";
}