微服务中常用的限流算法(二)

本文介绍了微服务中两种常用的限流算法——漏桶和令牌桶。漏桶算法限制请求处理速度,而令牌桶算法允许在一定范围内突发流量。文章提供了这两种算法的Java实现,并指出它们在实际应用中的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章微服务中常用的限流算法(一)中我们介绍了滑动窗口算法和滚动窗口算法和具体的实现代码,本篇文章我们介绍漏桶限流算法和令牌桶限流算法。

漏桶限流算法

漏桶限流算法是模拟水流过一个有漏洞的桶进而限流的思路。
在这里插入图片描述

水龙头的水先流入漏桶,再通过漏桶底部的孔流出。如果流入的水量太大,底部的孔来不及流出,就会导致水桶太满溢出去。限流器利用漏桶的这个原理设计漏桶限流算法,用户请求先流入到一个特定大小的漏桶中,系统以特定的速率从漏桶中获取请求并处理。如果用户请求超过限流,就会导致漏桶被请求数据填满,请求溢出,返回 503 响应。所以漏桶算法不仅可以限流,当流量超过限制的时候回拒绝处理,直接返回503响应,还能控制请求处理的速度,漏桶限流算法示意图如下:
在这里插入图片描述

在实现上,根据请求处理的事件间隔,例如:限流每秒10个请求,那么两个请求处理的时间间隔必须>=100ms,每个用户请求到达限流器后,根据当前最近一个请求处理的时间和最色的请求线程数目,计算当前线程sleep的时间,每个请求线程sleep的时间不同,最后就可以可以实现每隔100ms唤醒一个请求线程处理请求,从而达到漏桶限流的效果。漏桶限流限流算法的实现代码如下(父类定义在上一篇文章中):

public class LeakBucket extends AbstractLimitAlgo {

    private int interval;
    private int blockTask = 0;

    public LeakBucket(int limit,int interval) {
        super(limit);
        this.interval = interval;
    }

    @Override
    public boolean tryAcquire() {
        if(getElapseTimeFromLast() >= interval && blockTask <= 0) {
            lastTimeStamp = System.currentTimeMillis();
            return true;
        }

        if(blockTask > limit) {
            return false;
        }

        blockTask++;
        long sleep = interval * (++blockTask) - getElapseTimeFromLast();
        try {
            Thread.sleep(sleep);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lastTimeStamp = System.currentTimeMillis();
        blockTask--;
        return true;
    }
}

细心的老铁会发现,漏桶算法的限流策略,只能使请求按照一定的时间间隔处理,即使当前资源比较空闲,漏桶也只能慢慢的一个一个的处理,这其实不太符合人们的期望,因为这样就是在浪费计算资源。上述漏桶算法实现代码,存在一定的线程安全问题,如果要保证线程安全,需要增加一些额外的代码,反而使算法实现变得更加复杂,本文重点说明算法思路,对于线程安全问题,读者可以自行在本地实现。

令牌桶限流算法

令牌桶是另一种桶限流算法,模拟一个特定大小的桶,然后向桶中以特定的速度放入令牌(token),请求到达后,必须从桶中取出一个令牌才能继续处理。如果桶中已经没有令牌了,那么当前请求就被限流,返回 503 响应。
在这里插入图片描述

上面的算法描述似乎需要有一个专门线程生成令牌,还需要一个数据结构模拟桶。实际上,令牌桶的实现,只需要在请求获取令牌的时候,通过时间计算,就可以算出令牌桶中的总令牌数,实现代码如下:

public class TokenBucket extends AbstractLimitAlgo {

    private int limit;
    private int count = 0;
    private long lastTimeStamp ;

    // 流速控制
    private long interval;

    public TokenBucket(int limit, long interval) {
        super(limit);
        this.interval = interval;
    }

    @Override
    public boolean tryAcquire() {
        if(count >= 1) {
            count--;
            return true;
        }
        count= Math.min(limit,count + Long.valueOf(getElapseTimeFromLast() / interval).intValue());
        if(count >= 1) {
            count--;
            return true;
        }
        return false;
    }

}

令牌桶限流算法,可以根据桶内剩余令牌的多少,来影响请求处理的速度,例如一段时间内,没有用户请求,使令牌桶内积攒一部分令牌 ,那么此时 如果来了一波流量的话,那么可以在短时间内,获取到桶内所有令牌,是这波流量同时被处理,也就是说,使用令牌桶限流算法,并不会限制请求处理的速度,后端服务处理请求的峰值为令牌桶的容量。所以在设置令牌桶容量时,可以参考后端服务可以处理流量的峰值。同样令牌桶算法的实现代码也存在线程安全问题,读者可自行解决线程安全问题。

令牌桶限流算法综合效果比较好,能在最大程度利用系统资源处理请求的基础上,实现限流的目标。

总结

小编用了两篇文章 微服务中常用的限流算法(一) 和 微服务中常用的限流算法(二),讨论了在微服务中常用的限流算法和对应的代码实现,除了上文中提到的四种限流算法外,你还只知道哪些限流算法吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值