单机限流算法汇总

/**
 * 计数器限流
 * 计 数器法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,
 * 我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开 始的时候,
 * 我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,
 * 如果counter的值大于100并且该请求与第一个 请求的间隔时间还在1分钟之内,那么说明请求数过多;
 * 如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter,
 *
 *      * 缺陷:假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,
 *      * 那么其实这个用户在 1秒里面,瞬间发送了200个请求。我们刚才规定的是1分钟最多100个请求,
 *      * 也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。
 *      * 用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。
 */
private static long timestamp = System.currentTimeMillis();
//限制1S内100个请求
private static long limitcount = 100;
//间隔
private static long interval = 1000;
//请求数量
private static long requestCount = 0;

public static boolean grant(){
    long now =  System.currentTimeMillis();
    if(now < timestamp + interval){
        if(requestCount < limitcount){
            ++requestCount;
            return true;
        }else {
            return  false;
        }
    }else {
        timestamp = System.currentTimeMillis();
        requestCount = 0;
        return false;
    }
}
@Test
public  void testLimit(){
    for (int i = 0; i < 500; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
               if(grant()){
                   System.out.println("执行业务");
               }else {
                   System.out.println("限流");
               }
            }
        }).start();
    }
}

/**
 * 漏桶算法
 * 首先,我们有一个固定容量的桶,有水流进来,也有水流出去。对于流进来的水来说,我们无法预计一共有多
 * 少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这个桶可以固定水流出的速率。而且,
 * 当桶满了之后,多余的水将会溢出。
 *
 * 我们将算法中的水换成实际应用中的请求,我们可以看到漏桶算法天生就限制了请求的速度。
 * 当使用了漏桶算法,我们可以保证接口会以一个常速速率来处理请求。所以漏桶算法天生不会出现临界问题。
 */
//时间刻度
private static long time = System.currentTimeMillis();

//桶里面现存水
private static int water = 0;
//桶的大小
private static int size = 10;
//出水速度
private static int rate = 3;

public static boolean grant02(){
    long now = System.currentTimeMillis();
    int out = (int) ((now - time) * rate);
    water = Math.max(0,water - out);
    time = now;
    if((water + 1) < size){
        ++water;
        return true;
    }else {
        return  false;
    }
}
@Test
public  void testLimit02(){
    for (int i = 0; i < 500 ; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(grant02()){
                    System.out.println("执行业务");
                }else {
                    System.out.println("限流");
                }
            }
        }).start();
    }
}

/**
 * 令牌桶算法
 * 首先,我们有一个固定容量的桶,桶里存放着令牌(token)。桶一开始是空的,token以
 * 一个固定的速率r往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。每当一个请求过来时,
 * 就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通 过。
 *
 * 漏桶的出水速度是恒定的,那么意味着如果瞬时大流量的话,将有大部分请求被丢弃掉(也就是所谓的溢出)。
 * 为了解决这个问题,令牌桶进行了算法改进
 */
//private static long time = System.currentTimeMillis();
//令牌流速
private  static  int createTokenRate = 3;

private static int sizeToken = 10;
//当前令牌数
private static int tokens = 0;

public static boolean grant03(){
    long now = System.currentTimeMillis();

    int in = (int) ((now - time) * createTokenRate);

    tokens = Math.min(sizeToken,tokens + in);
    time = now;
    if(tokens > 0){
        --tokens;
        return true;
    }else {
        return false;
    }
}
@Test
public  void testLimit03(){
    for (int i = 0; i < 500 ; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(grant03()){
                    System.out.println("执行业务");
                }else {
                    System.out.println("限流");
                }
            }
        }).start();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_22899021/article/details/80845769