常见的限流算法
漏桶算法
一个固定容量的漏桶,按照设定常量固定速率流出水滴,类似医院打吊针,不管你源头流量多大,我设定匀速流出。
如果流入水滴超出了桶的容量,则流入的水滴将会溢出了(被丢弃),而漏桶容量是不变的
漏桶算法的缺点:
- 无法应对突发流量:漏桶中的水量有限,当突发流量到来时,漏桶可能会被填满,导致请求被拒绝。这意味着漏桶算法不能有效地防止突发流量对系统造成影响。
- 不适合瞬时高并发:漏桶算法对于业务高并发的场景,如秒杀、抢购、整点打卡签到、微博热点事件等,不够适用。在这些场景中,漏桶算法会缓存请求,避免系统出现雪崩效应,但处理速度可能会变慢。
令牌桶算法
用于控制单位时间内的请求数量,并允许突发数据的发送。
算法原理:
- 令牌桶算法维护一个固定容量的令牌桶。
- 每秒钟会向令牌桶放入一定数量的令牌。
- 当有请求到来时,如果令牌桶中有足够的令牌,则请求被允许通过并从令牌桶中消耗一个令牌。
- 如果令牌桶为空,请求将被拒绝。
滚动时间窗算法
允许固定数量的请求进入(比如1秒取4个数据相加,超过25值就over)超过数量就拒绝或者排队,等下一个时间段进入。
由于是在一个时间间隔内进行限制,如果用户在上个时间间隔结束前请求(但没有超过限制),同时在当前时间间隔刚开始请求(同样没超过限制),在各自的时间间隔内,这些请求都是正常的。
缺点:由于计数器算法存在时间临界点缺陷,因此在时间临界点左右的极短时间段内容易遭到攻击。
假如设定1分钟最多可以请求100次某个接口,如12:00:00-12:00:59时间段内没有数据请求但12:00:59-12:01:00时间段内突然并发100次请求,紧接着瞬间跨入下一个计数周期计数器清零;在12:01:00-12:01:01内又有100次请求。那么也就是说在时间临界点左右可能同时有2倍的峰值进行请求,从而造成后台处理请求加倍过载的bug,导致系统运营能力不足,甚至导致系统崩溃,/(ㄒoㄒ)/~~
滑动时间窗口算法
顾名思义,该时间窗口是滑动的。所以,从概念上讲,这里有两个方面的概念需要理解:
-
窗口:需要定义窗口的大小
-
滑动:需要定义在窗口中滑动的大小,但理论上讲滑动的大小不能超过窗口大小
滑动窗口算法是把固定时间片进行划分并且随着时间移动,移动方式为开始时间点变为时间列表中的第2个时间点,结束时间点增加一个时间点,
不断重复,通过这种方式可以巧妙的避开计数器的临界点的问题。下图统计了5次
配置Resilience的限流机制
- 引入依赖
<!--resilience4j-ratelimiter-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
- 配置yaml文件
####resilience4j ratelimiter 限流的例子
resilience4j:
ratelimiter:
configs:
default:
limitForPeriod: 2 #在一次刷新周期内,允许执行的最大请求数
limitRefreshPeriod: 1s # 限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
timeout-duration: 1 # 线程等待权限的默认等待时间
instances:
cloud-payment-service:
baseConfig: default
- 业务类方法上添加注解
@RateLimiter(name = "cloud-payment-service",fallbackMethod = "myRatelimitFallback")
- 编写降级方法
public String myRatelimitFallback(Integer id,Throwable t)
{
return "你被限流了,禁止访问/(ㄒoㄒ)/~~";
}