「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
计数器算法
计数器算法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开 始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多;如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter,具体算法的示意图如下:
具体步骤:
- 设置一个计数器统计单位时间内某个请求的访问量。
- 在进入下一个单位时间内把计数器清零
- 对于单位时间内超过计数器的访问,可以放入等待队列、直接拒接访问等策略
优点:简单
缺点:粗暴,易造成突刺现象。
漏斗算法
漏桶作为计量工具时,可用于流量整形和流量控制,漏桶的主要概念如下:
- 一个固定容量的漏桶,按照常量固定速率流出水滴(流出请求)
- 如果桶是空的,则不需流出水滴
- 可以以任意速率流入水滴到漏桶(流入请求)
- 如果流入水滴超出了桶的容量,则流入的水滴溢出了(新流入的请求被拒绝),则漏桶容量是不变的
漏桶可以看做固定容量、固定流出速率的队列,漏桶限制的是请求的流出速率,漏桶中装的是请求。
优点:稳定速率
缺点:无法面对突发流量
令牌桶算法
令牌桶算法,其核心是要想通过限流器,必须拿到令牌。也就是说,只要我们能够限制发放令牌的速率,那么就能控制流速了。令牌桶算法的详细描述如下:
- 令牌以固定的速率添加到令牌桶中,假设限流的速率是 r 个/秒,则令牌每 1/r 秒会添加一个;比如每秒放10个,每6秒放一个。
- 假设令牌桶的容量是 b ,如果令牌桶已满,则新的令牌会被丢弃;
- 每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。
这个算法中,限流的速率r还是比较容易理解的,但令牌桶的容量 b 该怎么理解呢?b 其实是burst的简写,意思是限流器允许的最大突发流量。比如b=10,而且令牌桶中的令牌已满,此时限流器允许10个请求同时通过限流器,当然只是突发流量而已,这10个请求会带走10个令牌,所以后续的流量只能按照速率 r 通过限流器。
优点:速率可变,能够面对突发流量
缺点:复杂度高
开源工具:Guava RateLimiter
RateLimiter是Guava的一个限流组件,它是基于令牌桶算法的,API非常简单
引入pom
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
具体例子:
public class Test {
public static void main(String[] args) throws Exception{
//线程池
ExecutorService exec = Executors.newCachedThreadPool();
//速率是每秒只有3个许可
final RateLimiter rateLimiter = RateLimiter.create(3.0);
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
boolean token = rateLimiter.tryAcquire();
if (token) {
System.out.println("token pass");
} else {
System.out.println("token refuse");
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
//执行线程
exec.execute(runnable);
}
//退出线程池
exec.shutdown();
}
}
主要接口:
创建实例接口
create(double permitsPerSecond)
create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) 预热模式创建,平滑过渡
获取permits
acquire(int permits) 阻塞模式获取,直到等到permits数量满足要求。
tryAcquire(long timeout, TimeUnit unit) 指定超时时间获取
tryAcquire(int permits) 非阻塞模式获取
本文已参与「新人创作礼」活动,一起开启掘金创作之路。