四种限流算法

四种限流算法

为什么要限流

限流是为了防止系统突然收到大量请求,后台面对大量并发请求对cpu和内存,网络io产生巨大压力,可能将一些服务如mysql,redis等打崩,引发系统故障,服务瘫痪。

固定窗口:Fixed Window Rate Limiting Algorithm

将时间分为固定窗口,将请求按时间顺序放入时间窗口,如果超过设置时间窗口的阈值就返回限流结果,但是在两个时间窗口替换间隙可能会有2n请求并发。

优点:实现简单,便于理解

缺点:存在明显的临界问题,切换间隙可产生产生2n请求:0.75秒-1.0秒产生n个请求,刷新,1.0-1.5s又产生n个请求,这n个请求各自窗口满足要求,但是再它门组成的窗口中并发量达到了2n

public class FixedWindow {
   
    //窗口大小
    private final static Integer timeUnit=1000;
    //请求计数
    private  AtomicInteger count=new AtomicInteger();

    private  Long lastTime=0L;

    private Integer  threshold=10;

    public boolean fixedWindow()
    {
   
          long currentTime=System.currentTimeMillis();
          if(currentTime-lastTime>timeUnit)
          {
   
              count.set(0);
              lastTime=currentTime;
          }
          if(count.get()>=threshold) //初始计数是0 ,所以是大于等于刚好执行十次
          {
   
              return false;
          }
          count.getAndIncrement();
          return true;
    }

    public static void main(String[] args) {
   
        FixedWindow fixedWindow=new FixedWindow();
        for(int i=0;i<20;i++)
        {
   
            System.out.println(fixedWindow.fixedWindow());
        }
    }

}

滑动窗口:Sliding Windows Algorithm

将单位时间周期又划分成n个小周期,分别根据每个小周期内接口的访问次数,并根据时间滑动自动删除过期的小周期(tcp就是根据这个来实现对发送字节的大小控制)

优点: 简单易懂,精度高可以调整时间粒度来调节限流效果,可拓展性,可与和其他限流算法结合使用

缺点:无法应对突发请求,突发请求会被大量拒绝,会损失大量请求

public class SlidingWindow {
   


    private final int maxRequests; // 最大请求数
    private final long timeWindowMillis; // 时间窗口(毫秒)
    private final Queue<Long> requests; // 请求队列

    public SlidingWindow(int maxRequests, long timeWindowMillis) {
   
        this.maxRequests = maxRequests;
        this.timeWindowMillis = timeWindowMillis;
        this.requests = new LinkedList<>();
    }

    public synchronized boolean tryAcquire() {
   
        // 移除超出时间窗口的请求
        while (!requests.isEmpty() && System.currentTimeMillis() - requests.peek() > timeWindowMillis) {
   
            requests.poll();
        }

        // 判断当前窗口内的请求数量是否超过最大请求数
        if (requests.size() < maxRequests) {
   
            // 添加新请求到队列
            requests.offer(System.currentTimeMillis());
            return true;
        } else {
   
            return false;
        }
    }
    public static void main(String[] args) throws InterruptedException {
   

        SlidingWindow rateLimiter = new SlidingWindow(5, 1000); // 每秒最多5个请求

        for (int i = 0; i < 20; i++) {
   
            System.out.println("Request " + (i + 1) + ": " + (rateLimiter.tryAcquire() ? "Accepted" : "Rejected"));
        }

    }
}

漏桶算法:Leaky Bucket Algorithm

控制流入网络的速率速度,以防止网络堵塞。核心思想就是将请求比作小水滴,漏桶看作固定容量的水桶,数据包从顶部进入漏桶,漏桶底部以匀速形式流出数据包。水满则溢,拒绝请求。

优点:可以十分平滑的处理请求,对瞬间增加的请求有一定的承载能力

缺点:需要对请求进行缓存,会增加服务器的内存消耗。面对突发流量无法进行快速处理请求。

public class LeakyBucket {
   
    private int capacity = 10;
    private int rate = 1;  //每ms多少个
    private int total = 0;
    private long lastTime = System.currentTimeMillis();

    private synchronized boolean leakBucket(Integer water) throws InterruptedException {
   
        long time=System.currentTimeMillis();
        long escapeTime=time-lastTime;
        long leakWater=escapeTime*rate;
        if(leakWater>0)
        {
   
            total=(int) Math.max(0,total-leakWater);
            lastTime=time;
        }
        if(total+water>capacity)
        {
   
            Thread.sleep(4);
            return false;
        }
        total=total+water;
        return true;
    }

    public static void main(String[] args) throws InterruptedException {
   
        LeakyBucket leakyBucket=new LeakyBucket();
        for (int i = 0; i < 20; i++) {
   
            System.out.println(leakyBucket.leakBucket(2));
        }
    }
}

令牌桶算法:Token Bucket Algorithm

系统以一定的速率向令牌桶中添加令牌,请求到来时先去尝试获取令牌,拿到令牌就正常请求并消耗这个令牌,拿不到就拒绝服务。

优点:可以应对突发流量,具有弹性处理请求的特点,稳定性好。精度高:可以根据请求动态调节生成令牌桶的速率

缺点:实现复杂,时间精度控制要求比较高

public class TokenBucket {
   
    private long capacity = 5;//令牌总数
    private long lastTime=System.currentTimeMillis();
    private long  rate=5;//每毫秒发放令牌
    private long  total=capacity;
    private synchronized boolean tokenBucket() throws InterruptedException {
   
        long now=System.currentTimeMillis();
        long gap=now-lastTime;
        long add=gap*rate;
        if(total<20)
        {
   
            total=Math.min(total+add,capacity);
            lastTime=now;
        }
        if(total-1<0)
        {
   
            Thread.sleep(1);
            return false;
        }
        total--;
        return true;
    }

    public static void main(String[] args) throws InterruptedException {
   
        TokenBucket tokenBucket=new TokenBucket();
        for (int i = 0; i < 20; i++) {
   
            System.out.println(tokenBucket.tokenBucket());
        }
    }
}

相关推荐

  1. 算法

    2024-01-04 15:12:12       41 阅读
  2. 算法学习

    2024-01-04 15:12:12       14 阅读
  3. RateLimiter 算法使用

    2024-01-04 15:12:12       9 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-04 15:12:12       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-04 15:12:12       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-04 15:12:12       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-04 15:12:12       20 阅读

热门阅读

  1. vue3如何用了按需引入组件如何修改ant的主题颜色

    2024-01-04 15:12:12       41 阅读
  2. 80机华南独山更改点算法--对每个循环显示的优化

    2024-01-04 15:12:12       38 阅读
  3. Vue2/Vue3-插槽(全)

    2024-01-04 15:12:12       39 阅读
  4. 前后端项目统一返回类型(配置即用)

    2024-01-04 15:12:12       37 阅读
  5. oracle 子查询和窗口函数

    2024-01-04 15:12:12       44 阅读
  6. 深度学习必备框架PyTorch简介和参考资料

    2024-01-04 15:12:12       42 阅读
  7. python&Pandas二:数据读取与写入

    2024-01-04 15:12:12       39 阅读
  8. 原码、反码、补码,计算机中负数的表示

    2024-01-04 15:12:12       26 阅读
  9. 连接字符串

    2024-01-04 15:12:12       37 阅读
  10. 分布式【ZooKeeper面试题】

    2024-01-04 15:12:12       28 阅读