深入解析限流的三种算法:信号量、漏桶算法和令牌桶算法的实现与应用
当前限制的三种算法

当前有三种主要的限制算法:信号量,泄漏的铲斗算法和令牌桶算法。
信号量限制并发和资源。令牌存储桶限制QPS。
信号
信号量是计数信号量。它通常用于限制获得某个资源的线程数,并且可以根据Java并发并发软件包实现。
通过ACCEARIE()方法获得许可,该方法将阻塞直到获得许可。
通过Release()方法发布权限。
基于Java的并发实施
@RestController
@RequestMapping("/semaphore")
public class SemaphoreController {
//初始化信号量=5,true-公平信号量FIFO。
private Semaphore semaphore = new Semaphore(5, true);
@RequestMapping("/acquire/{par1}")
public String acquire(@PathVariable String par1){
try {
semaphore.acquire(1);//获取一个许可
//do sth
return par1+"获取一个许可";
}catch (InterruptedException e){
e.printStackTrace();
return "获取许可失败";
}catch (Exception e1){
return "获取许可失败";
}finally {
semaphore.release(1);//处理完后,释放一个许可
}
}
}
泄漏桶算法
泄漏的水桶算法有一个简单的想法。水(要求)首先进入漏水的水桶。泄漏的水桶以一定速度出现(接口具有响应率)。当水流过高时,它将直接溢出(访问频率超过接口响应。)然后拒绝请求,可以看出,泄漏的存储桶算法可以强行限制数据传输速率。示意图如下:
泄漏桶算法
令牌桶算法
令牌桶算法(令牌桶)和漏水桶具有相同的效果,但方向相反,易于理解。随着时间的流逝,系统将以常数的1/QPS时间间隔(如果QPS = 100,间隔为10ms)添加令牌添加令牌(假设它与漏洞相反,则有一个水龙头不断添加水)。如果存储桶已满,则不会添加它。当新请求到来时,每个请求都会带走一个令牌。如果没有令牌,它将阻止或拒绝服务
令牌桶算法
令牌桶算法比泄漏的水桶算法更优雅,并且适用于诸如Flash Sale之类的场景。此示例主要描述了基于Google的Guava代币算法的实现。
POM坐标,建议使用16.0及以上版本
com.google.guava
guava
25.0-jre
当前限制实现
@RestController
@RequestMapping("/ratelimiter")
public class RateLimiterController {
private RateLimiter rateLimiter = RateLimiter.create(0.5);//每秒发放0.5个令牌。注意:本初始化声明不要放在方法内
//非阻塞机制
@RequestMapping("/nonblock")
public String rateLimiterNonBlock() {
//如果令牌桶内有令牌,则直接发放;如果能在1000ms内能够获取一个令牌,则等待到时后发放;如果在1000ms内无法获取令牌,则直接返回false,无需等待。
if (rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
//do sth
return "成功获取令牌";
} else {
// do other
return "获取失败";
}
}
//阻塞机制
@RequestMapping("/block")
public String reateLimiterBlock(){
//获取一个令牌,该方法会被阻塞知道获取令牌
double waitTime = rateLimiter.acquire();
//do sth
return "等待"+waitTime+"秒后,成功获取令牌";
}
}
建议使用非阻滞方法。
方法摘要
修饰符和类型方法描述
双倍的
获得()
获得Ratelimiter的许可,该方法将被阻止,直到检索请求
双倍的
获取(INT许可)
从Ratelimiter获取指定的权限号,该方法将被阻止,直到检索请求
静态比率
创建(双重允许)
基于指定的稳定吞吐率创建比例比率,其中吞吐量率是指每秒许可证数量(通常,QPS,每秒多少查询)
静态比率
创建(双允许允许长时间的harmuperpiood,时间单位单元)
根据指定的稳定吞吐量和热身时期创建比率的比率。在这里,吞吐量是指每秒许可证数量(通常是QP,每秒多少个请求)。在此热身时间,每秒比率的比率分配的许可证数量将顺利增长,直到在热身期结束时达到其最大速度为止。 (只要有足够的请求使其饱和)
双倍的
getrate()
返回稳定的比率配置,每秒的许可证数量
空白
setrate(双允许秒)
更新稳定的ratelimite速率,参数允许允许通过构造ratelimite的工厂方法提供。
布尔
TryAcquire()
如果立即获得许可证,请立即获得许可证
布尔
TryAcquire(INT许可)
如果可以立即获取许可证号,请立即获得许可证号
布尔
tryAcquire(int许可,长时间,时机单元)
如果可以在超时时间内获得许可证,或者如果超时,或者在超时到期之前无法获得许可证,请从Ratelimiter获取指定的许可证
布尔
tryAcquire(长时间,时间单元)
如果可以在不超时的超时期内获得许可证,或者如果超时到期之前获得许可证,请从Ratelimiter获得许可证
参考: