限流算法-令牌桶算法:
如上图所示,随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token,如果桶已经满了就不再加了.
新请求来临时,会各自拿走N(N≥1)个Token,如果没有Token可拿了就阻塞或者拒绝服务.
由上述算法原理描述,我们可以得出,限制速率的方式有两种,
1) 控制令牌生成的速率;
2) 控制消耗令牌的速率;
基于令牌桶算法,google开源工具包提供了一个限流工具类RateLimiter。RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率.它支持两种获取permits接口,一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到,后续我们会针对这两种接口进行阐述 。
RateLimiter工具类:
写在最前:
相关pom依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
接口定义:(加粗的为日常用到的方法)
接口名称
|
接口释义
|
---|---|
static RateLimiter create(double permitsPerSecond) | 根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)(设定速率的地方之一) |
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) | 根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)(该方法用于某些数据或请求需要预热的场景)参数含义 :qps,预热时长 ,预热时长的时间单位 |
double acquire() | 从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求(默认是1)(请求会阻塞 ) |
double acquire(int permits) | 从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求(设定速率的地方之一,请求会阻塞 ) |
boolean tryAcquire() | 从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话(默认是1)(不会阻塞请求,获取不到token,直接返回失败,适用于允许快速失败的场景) |
boolean tryAcquire(int permits) | 同tryAcquire(),获取N个许可 |
boolean tryAcquire(long timeout, TimeUnit unit) | 从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)(非阻塞,超出等待时间立即返回失败) |
boolean tryAcquire(int permits, long timeout, TimeUnit unit) | 同tryAcquire(long timeout, TimeUnit unit) |
double getRate() | 返回RateLimiter 配置中的稳定速率,该速率单位是每秒多少许可数 |
void setRate(double permitsPerSecond) | 更新RateLimite的稳定速率,参数permitsPerSecond 由构造RateLimiter的工厂方法提供。 |
String toString() | 返回对象的字符表现形式 |
方法使用示例:
第一步:声明RateLimiter对象
public static final RateLimiter limiter = RateLimiter.create(500.0); //qps:500
或者
public static final RateLimiter limiter = RateLimiter.create(500.0,10,TimeUnit.SECONDS); //qps:500 预热期:10S(在10S内,qps逐步上升到500/s)
第二步:在需要进行速率限制的地方,获取令牌
for (Runnable task : tasks) {
limiter.acquire(); // 需要等待(请求会被阻塞 ,直到获取到令牌才执行)
xxxxxx;//执行任务逻辑
}
或者
for (Runnable task : tasks) {
boolean result = limiter.tryAcquire(); // 不需要等待(请求不会阻塞 )
if(result){
xxxxxx; //获取到令牌,执行相关任务逻辑
}else{
continue; //未获取到令牌,快速失败
}
}
以上是个人对RateLimiter工具类在日常项目中的一些理解和使用,如有不正确的地方,欢迎指正 ,也可自行完善/修改文中内容。
参考资料:
- https://google.github.io/guava/releases/19.0/api/docs/index.html?com/google/common/util/concurrent/RateLimiter.html(官方API)
- http://ifeve.com/guava-ratelimiter/ (官方API 译文)
viagra pros y contras Wicmymmele https://ascialis.com/# – Cialis gaideleplete Cephalexin For Horses affextop Cialis adoreakder Effet Cialis Ou Viagra
Cialis En Gibraltar Wicmymmele https://cialiser.com/ – Cialis gaideleplete buy brand name accutane affextop safe cialis online adoreakder pastillas cialis barato
cialis viagra combo pack
buy cialis online prescription
order cialis online
cialis online ordering
best place to buy cialis online forum
https://bestadalafil.com/ – purchase cialis Qi A Pris Du Cytotec cialis viagra combo pack Fclmkz precio cialis €0.77 https://bestadalafil.com/ – Cialis