服务限流算法:从令人头疼到信手拈来

66 篇文章 1 订阅

前言

随着系统规模的扩大和用户量的增加,服务限流成为了一个非常重要的话题。一方面,系统需要能够处理大量的请求,不至于因为负载过高而崩溃;另一方面,又需要避免恶意攻击或者其他异常情况对系统造成影响。本文将介绍一些常见的服务限流算法,包括漏桶算法、令牌桶算法、计数器算法等,并提供Java实现示例,帮助读者更好地理解这些算法。

漏桶算法

算法原理

漏桶算法是一种最简单的限流算法。它的基本思想是,将请求看作是水流,服务则是下面的水桶。当请求进来时,先放到容量固定的漏桶中,然后以一定的速度流出。如果漏桶已经满了,那么新的请求就会被丢弃。这个速度可以是固定的,也可以是动态的,与具体实现有关。

漏桶算法可以有效平滑流量,控制请求处理的速度。

Java实现

public class LeakyBucket {
    private final int capacity; // 漏桶容量
    private final int ratePerSecond; // 水流出的速度(每秒)
    private int waterLevel = 0; // 桶中当前水位
    private long lastUpdateTime = System.currentTimeMillis(); // 上次更新时间

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

    public synchronized boolean allowRequest() {
        // 计算时间差,更新漏桶中的水量
        long timePassed = System.currentTimeMillis() - lastUpdateTime;
        int waterDrained = (int) (timePassed / 1000 * ratePerSecond);
        waterLevel = Math.max(0, waterLevel - waterDrained);
        lastUpdateTime = System.currentTimeMillis();

        // 判断漏桶中的水量是否超过容量,如果超过则拒绝请求
        if (waterLevel >= capacity) {
            return false;
        } else {
            waterLevel++;
            return true;
        }
    }
}

漏桶算法的Java实现非常简单,只需要记录漏桶的容量和速度,并在处理请求时更新漏桶中的水位即可。在上述示例中,使用synchronized关键字确保线程安全。

令牌桶算法

算法原理

令牌桶算法也是一种常见的限流算法。它的基本思想是,系统以一定的速度生成令牌并放入桶中,请求需要从桶中取出令牌才能被处理。如果桶中没有令牌,则请求不能被处理。这个速度可以是固定的,也可以是动态的,与具体实现有关。

令牌桶算法可以控制请求处理的速率,同时还可以应对短时间内的请求突发。

Java实现

public class TokenBucket {
    private final int capacity; // 令牌桶容量
    private final int ratePerSecond; // 令牌生成速度(每秒)
    private int tokenCount = 0; // 桶中当前令牌数
    private long lastUpdateTime = System.currentTimeMillis(); // 上次更新时间

    public TokenBucket(int capacity, int ratePerSecond) {
        this.capacity = capacity;
        this.ratePerSecond = ratePerSecond;
    }

    public synchronized boolean allowRequest() {
        // 计算时间差,更新桶中的令牌数
        long timePassed = System.currentTimeMillis() - lastUpdateTime;
        int tokensToAdd = (int) (timePassed / 1000 * ratePerSecond);
        tokenCount = Math.min(capacity, tokenCount + tokensToAdd);
        lastUpdateTime = System.currentTimeMillis();

        // 判断令牌数是否足够,如果足够则允许请求
        if (tokenCount > 0) {
            tokenCount--;
            return true;
        } else {
            return false;
        }
    }
}

令牌桶算法的Java实现与漏桶算法类似,只需要记录令牌桶的容量和速度,并在处理请求时更新桶中的令牌数即可。在上述示例中,使用synchronized关键字确保线程安全。

计数器算法

算法原理

计数器算法是一种基于时间窗口的限流算法。它的基本思想是,用一个定长的时间窗口来统计请求次数,当请求次数超过阈值时,则拒绝新的请求。这个时间窗口可以是固定的,也可以是动态的,与具体实现有关。

Java实现

public class Counter {
    private final int maxRequests; // 时间窗口内最大请求数
    private final long timeWindowInMillis; // 时间窗口长度(毫秒)
    private final Queue<Long> requestTimes = new LinkedList<>(); // 请求时间队列

    public Counter(int maxRequests, long timeWindowInMillis) {
        this.maxRequests = maxRequests;
        this.timeWindowInMillis = timeWindowInMillis;
    }

    public synchronized boolean allowRequest() {
        // 移除过期的请求时间
        long currentTime = System.currentTimeMillis();
        while (!requestTimes.isEmpty() && requestTimes.peek() < currentTime - timeWindowInMillis) {
            requestTimes.poll();
        }

        // 判断请求数是否达到阈值
        if (requestTimes.size() < maxRequests) {
            requestTimes.offer(currentTime);
            return true;
        } else {
            return false;
        }
    }
}

计数器算法的Java实现需要使用一个队列来存储请求时间,并在处理请求时动态地移除过期的请求时间。在上述示例中,使用synchronized关键字确保线程安全。

总结

本文介绍了三种常见的服务限流算法,漏桶算法、令牌桶算法和计数器算法,以及它们在Java中的实现。这些算法在实际应用中都有自己的优缺点,大家可以根据具体需求选择合适的算法。同时,也可以结合多种算法,形成更加严谨、可靠的限流策略。

👉 💐🌸 公众号请关注 "果酱桑", 一起学习,一起进步! 🌸💐

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值