限流器介绍
限流器是一种用来控制请求速率的工具,它可以防止系统过载,并确保系统能够平稳运行。限流器的原理很简单,它通过限制一段时间内可以处理的请求数量来实现限流。
限流器在哪里
这里我们的限流器一般使用在第三层,也就是在某个微服务实例中使用。
三层限流
1层
nginx 限制ip的访问频率。
2层
Gateway中通过用户的唯一标识限制同一个用户的访问频率。
3层
微服务中限制业务访问的频率。
第三层直接应对的我们具体的业务,最接近开发者也最接近用户的功能,所以限流是相当重要。
限流器的应用场景
- 限制资源消耗:例如,限制对数据库的查询频率,或者限制对文件系统的写入速度,以防止资源枯竭。
- 防止过载:例如,限制对Web服务的请求频率,或者限制对消息队列的发送速度,以防止系统过载。
- 平滑流量:例如,来平滑的对某个服务的请求流量,以防止服务出现抖动。
- 实现令牌桶算法:令牌桶算法是一种经典的限流算法,可以很容易地实现令牌桶算法。
- 实现漏桶算法:漏桶算法也是一种经典的限流算法,可以很容易地实现漏桶算法,一般可通过队列实现。
限流器通常使用方法
- 创建一个 限流器 对象。
- 调用对象的acquire()方法来获取一个令牌。
- 在获取到令牌之后,你就可以执行受限的操作了。
- 重复步骤2和步骤3,直到你的操作完成。
手撸限流器
这里我们使用java来自定义一个限流器
AccessLimiter 类
职责:
- 限制对资源的并发访问的限制。
属性:
- **name:**限流器的名称。
- **rate:**每秒生成的令牌数。
- **capacity:**令牌桶的最大容量。
- **tokens:**当前令牌数。
- **scheduler:**用于定时任务的线程池。
- **warmupPeriod:**预热时间(秒)。
- **warmupTimeUnit:**预热时间单位。
- **isRunning:**限流器是否正在运行。
方法:
- **constructor:**构造函数。
- **getName:**获取限流器的名称。
- **start:**开始运行限流器。
- **refreshTokens:**刷新令牌。
- **warmup:**令牌预热。
- **tryAcquire:**尝试获取得到令牌,如果失败则阻塞直到成功或超时。
- **allowed:**允许通过。
- **throttled:**阻止通过。
- **stop:**停止限流器。
代码:
/**
*包名称
*/
package com.qcmb.java.utils.access;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* 访问限制器,工具类,此工具是根据令牌桶思想制作。
* 说明:
* 令牌桶的容量是有限的,
* 令牌的生成速率是均匀的。
* 并发请求的到达速率是均匀的。
* 参数作用:
* capacity【令牌桶】的作用:
* 在并发请求下限制并发请求的最大请求数量。
* 例如:令牌生成速率提高到 500,这个限流器最多也只能同时处理 1000 个并发请求
* rate【令牌生成速率】作用:
* 速率越低,令牌桶中令牌的生成速度就越慢。控制令牌桶中令牌的生成速度,那么也就间接的控制了并发请求数。
* 注意事项:
* 在实际应用中,令牌桶的容量和令牌生成速率需要根据实际情况进行调整。
* 如果【令牌桶】的容量太小,那么这个限流器子多线程下就无法处理足够的并发请求。
* 如果【令牌生成速率】太高,那么这个限流器就会开始丢弃令牌。
* 因此,需要根据实际情况调整令牌桶的容量和令牌生成速率,以实现最佳效果。
*/
public class AccessLimiter {
//监控器
private final IMonitor monitor;
private final Object lock = new Object();
/**
* 限流器的名称
*/
private final String name;
private final int rate; // 每秒生成的令牌数
private final int capacity; // 令牌桶的最大容量
/**
* 使用原子变量
*/
private final AtomicInteger tokens; // 当前令牌数
private final ScheduledExecutorService scheduler; // 用于定时任务的线程池
private final long warmupPeriod; // 预热时间(秒)
private final TimeUnit warmupTimeUnit; // 预热时间单位
private final AtomicLong warmupTime = new AtomicLong(0); //预热的执行时间
private vo