1. 限流算法

通过对并发访问请求进行限速,对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率可以拒绝服务、排队或等待、降级处理

  1. 计数器

控制单位时间内的请求数量。

劣势:设每分钟请求数量60个,每秒处理1个请求,用户在 00:59 发送 60 个请求,在 01:00 发送 60 个请求 此时 2 秒钟有 120 个请求( 每秒 60 个请求),远远大于了每秒钟处理数量的阈值。(突刺现象)

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {

    /**
     * 最大访问数量
     */
    private final int limit = 10;

    /**
     * 访问时间差
     */
    private final long timeout = 1000;

    /**
     * 请求时间
     */
    private long time;

    /**
     * 当前计数器
     */
    private AtomicInteger reqCount = new AtomicInteger(0);

    public boolean limit() {
        long now = System.currentTimeMillis();
        if (now < time + timeout) {
            //单位时间内
            reqCount.addAndGet(1);
            return reqCount.get() <= limit;
        } else {
            //超出单位时间
            time = now;
            reqCount = new AtomicInteger(0);
            return true;
        }
    }

}
  1. 滑动窗口

对计数器的一个改进,增加一个时间粒度的度量单位,一分钟分为若干份(如6份,没10秒一份),在每份上设置独立计数器,

  1. leaky bucket漏桶

规定固定容量的桶,进入的水无法管控数量、速度,但是对于流出的水我们可以控制速度

劣势:无法应对短时间突发流量(桶满了就丢弃)


public class LeakBucket {

    /**
     * 时间
     */
    private long time;

    /**
     * 总量
     */
    private Double total;

    /**
     * 水流出速度
     */
    private Double rate;

    /**
     * 当前总量
     */
    private Double nowSize;

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

        nowSize = Math.max(0, (nowSize - (now - time) * rate));
        time = now;

        if ((nowSize + 1) < total) {
            nowSize++;
            return true;
        } else {
            return false;
        }

    }
}
  1. Token Bucket令牌桶

规定固定容量的桶,token 以固定速度往桶内填充, 当桶满时 token 不会被继续放入, 每过来一个请求把 token 从桶中移除, 如果桶中没有 token 不能请求。 可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。

public class TokenBucket {

    /**
     * 时间
     */
    private long time;

    /**
     * 总量
     */
    private Double total;

    /**
     * 水流出速度
     */
    private Double rate;

    /**
     * 当前总量
     */
    private Double nowSize;


    public boolean limit() {

        long now = System.currentTimeMillis();

        nowSize = Math.min(total, (nowSize + (now - time) * rate));
        time = now;

        if (nowSize < 1) {
            //桶里没有token
            return false;
        } else {
            //存在token
            nowSize -= 1;
            return true;
        }
    }

}
Copyright & copy lviter@163.com            updated 2024-02-06 09:54:56

results matching ""

    No results matching ""