Guava —— RateLimiter 接口限流

限流==保险丝策略,可借助框架如spring cloud中Hystrix组件实现。今天介绍使用guava RateLimiter 类实现接口限流。

常见限流算法

漏桶算法

     漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.

     两个变量,一个是桶的大小即支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate),伪代码如下:


    double rate; // leak rate in calls/s
    double burst; // bucket size in calls
    long refreshTime; // time for last water refresh
    double water; // water count at refreshTime

    refreshWater() {
        long now = getTimeOfDay();
        //水随着时间流逝,不断流走,最多就流干到0.
        water = max(0, water - (now - refreshTime) * rate);
        refreshTime = now;
    }

    bool permissionGranted() {
        refreshWater();
        if (water < burst) { 
            // 水桶还没满,继续加1
            water++;
            return true;
        } 
        return false;
    }

令牌桶算法

     令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反,更容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

摘自:限流算法之漏桶算法、令牌桶算法

Guava RateLimiter 原理

基于令牌桶算法实现,以固定的频率(1秒)向桶中放入一定数量令牌,比如你希望自己的应用程序QPS不要超过1000,那么RateLimiter设置1000的速率后,就会每秒往桶里扔1000个令牌。业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请求才会被成功响应。获取的方式有两种:阻塞等待令牌或者取不到立即返回失败

非阻塞:立刻返回或doSomethingElse,不等待令牌

If(limiter.tryAcquire()){ //未请求到limiter则立即返回false
    doSomething();
}else{
    doSomethingElse();
}

阻塞:一直等待获取令牌


    final RateLimiter rateLimiter = RateLimiter.create(2.0);
    void submitTasks(List tasks, Executor executor) {
        for (Runnable task : tasks) {
            rateLimiter.acquire(); // may wait
            executor.execute(task);
        }
    }

Guava RateLimiter 应用

1、封装限流服务类

@Service
public class AccessLimitService {

    //每秒只发出5个令牌 ,超过permits会被阻塞
    //类似于JDK的信号量Semphore,用来限制对资源并发访问的线程数
    RateLimiter rateLimiter = RateLimiter.create(5.0);

    /**
     * 尝试获取令牌
     * @return
     */
    public boolean tryAcquire(){
        return rateLimiter.tryAcquire();
    }
}

2、限流接口执行业务代码前,先尝试获取令牌

    public String access(){
        //尝试获取令牌
        if(accessLimitService.tryAcquire()){
            //模拟业务执行500毫秒
            try {
                //dosth
                Thread.sleep(500);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return "access success";
        }
            return "access limited";
    }

Guava RateLimiter 主要API

Guava —— RateLimiter 接口限流_第1张图片

你可能感兴趣的:(【深入Java】)