美文网首页
漏桶限流算法

漏桶限流算法

作者: justonemoretry | 来源:发表于2023-03-05 17:59 被阅读0次

简介

漏桶限流,漏桶流出的速度是恒定的,流入速度不定,桶满时则抛弃请求,一般可用于保护三方接口,这样保证不超出限制的qps。对比令牌桶的话,在突发流量上会丢弃请求数更少,漏桶会有个请求排队的过程,只有漏桶装满了才会抛弃请求。
漏桶限流可以用在需要请求排队的场景,比如微博热点,秒杀之类的场景,可以利用漏桶缓存请求,对比令牌桶可以减少请求的丢弃

漏桶限流简单实现方法

这种实现方式在aquire时,先按设置的漏出速率计算桶内剩余水量,桶满了则拒绝请求,通过水数加1,这样其实并没有控制请求通过的速率,比如空桶的情况下,请求会一直通过,和设置的固定漏出速率没必然关系。

public final class LeakyBucket {
    // 桶的容量
    private int capacity = 10;
    // 木桶剩余的水滴的量(初始化的时候的空的桶)
    private AtomicInteger water = new AtomicInteger(0);
    // 水滴的流出的速率 每1000毫秒流出1滴
    private int leakRate;
    // 第一次请求之后,木桶在这个时间点开始漏水
    private long leakTimeStamp;

    public LeakyBucket(int capacity, int leakRate) {
        this.capacity = capacity;
        this.leakRate = leakRate;
    }

    public LeakyBucket(int leakRate) {
        this.leakRate = leakRate;
    }

    public boolean acquire() {
        // 如果是空桶,就当前时间作为桶开是漏出的时间
        if (water.get() == 0) {
            leakTimeStamp = System.currentTimeMillis();
            water.addAndGet(1);
            return capacity != 0;
        }
        // 先执行漏水,计算剩余水量
        int waterLeft = water.get() - ((int) ((System.currentTimeMillis() - leakTimeStamp) / 1000)) * leakRate;
        water.set(Math.max(0, waterLeft));
        // 重新更新leakTimeStamp
        leakTimeStamp = System.currentTimeMillis();
        // 尝试加水,并且水还未满
        if ((water.get()) < capacity) {
            water.addAndGet(1);
            return true;
        } else {
            // 水满,拒绝加水
            return false;
        }
    }
}

sentinel中漏桶限流实现

实际使用中sentinel的限流有个CONTROL_BEHAVIOR_RATE_LIMITER模式,采用漏桶算法,用最大排队等待时间去限制桶的容量,排队等待的线程进行休眠一段时间的操作,控制请求频率。

public class RateLimiterController implements TrafficShapingController {
    // 最大排队时间
    private final int maxQueueingTimeMs;
    // 每秒允许通过的qps
    private final double count;

    private final AtomicLong latestPassedTime = new AtomicLong(-1);

    public RateLimiterController(int timeOut, double count) {
        this.maxQueueingTimeMs = timeOut;
        this.count = count;
    }

    @Override
    public boolean canPass(Node node, int acquireCount) {
        return canPass(node, acquireCount, false);
    }

    @Override
    public boolean canPass(Node node, int acquireCount, boolean prioritized) {
        // Pass when acquire count is less or equal than 0.
        if (acquireCount <= 0) {
            return true;
        }
        // Reject when count is less or equal than 0.
        // Otherwise,the costTime will be max of long and waitTime will overflow in some cases.
        if (count <= 0) {
            return false;
        }

        long currentTime = TimeUtil.currentTimeMillis();
        // Calculate the interval between every two requests.计算单个请求漏出的时间
        long costTime = Math.round(1.0 * (acquireCount) / count * 1000);

        // Expected pass time of this request.
        long expectedTime = costTime + latestPassedTime.get();
        // 计算的预期耗时小于当前时间,放行
        if (expectedTime <= currentTime) {
            // Contention may exist here, but it's okay.
            latestPassedTime.set(currentTime);
            return true;
        } else {
            // 计算需要等待时间
            // Calculate the time to wait.
            long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis();
            if (waitTime > maxQueueingTimeMs) {
                return false;
            } else {
                long oldTime = latestPassedTime.addAndGet(costTime);
                try {
                    waitTime = oldTime - TimeUtil.currentTimeMillis();
                    // 等待时间过长
                    if (waitTime > maxQueueingTimeMs) {
                        latestPassedTime.addAndGet(-costTime);
                        return false;
                    }
                    // in race condition waitTime may <= 0
                    if (waitTime > 0) {
                        // 线程休眠,控制请求下发频率
                        Thread.sleep(waitTime);
                    }
                    return true;
                } catch (InterruptedException e) {
                }
            }
        }
        return false;
    }

}

参考文章

漏桶算法和令牌桶算法,区别到底在哪里?

相关文章

  • 基础架构 | 限流算法

    限流算法 令牌桶算法 漏桶算法

  • 【Guava】使用Guava的RateLimiter做限流

    一、常见的限流算法 目前常用的限流算法有两个:漏桶算法和令牌桶算法。 1.漏桶算法 漏桶算法的原理比较简单,请求进...

  • 限流框架系列之常见限流算法

    四种常见的限流算法 固定时间窗口限流算法 滑动时间窗口限流算法 令牌桶限流算法 漏桶限流算法 算法比较 算法确定参...

  • 高并发下的Nginx实用配置 - 限流和黑白名单

    1. 限流算法 漏桶算法 令牌桶算法 更多限流算法相关知识,请查看【单机限流 - 限流算法及隔离策略】[https...

  • 高并发下的限流算法

    对于限流常见有两种算法: 漏桶算法 令牌桶算法 漏桶算法 漏桶算法比较简单,就是将流量放入桶中,漏桶同时也按照一定...

  • 2020-06-09

    目录 代理层限流 容器限流 API 限流 时间窗口 漏桶算法 令牌桶算法 总结 为了保护暴露在公网...

  • 限流算法

    限流算法 漏桶算法 漏桶算法思路很简单,我们把水比作是请求,漏桶比作是系统处理能力极限,水先进入到漏桶里,漏桶里的...

  • RateLimiter限流

    一、常见的限流算法 1.漏桶算法 漏桶算法的原理比较简单,请求进入到漏桶中,漏桶以一定的速率漏水。当请求过多时,水...

  • Redis+Lua脚本三步实现分布式系统限流

      在分布式系统中,说到限流方案我们一般会使用redis结合限流算法来做,一般的限流算法有令牌桶算法、漏桶算法、固...

  • 你知道常见的限流算法有哪些吗?

    我们常见的限流算法有四种:计数器(固定窗口)算法、滑动窗口算法、漏桶算法、令牌桶算法。 为什么要限流 资源是有限的...

网友评论

      本文标题:漏桶限流算法

      本文链接:https://www.haomeiwen.com/subject/gonuldtx.html