专业的JAVA编程教程与资源

网站首页 > java教程 正文

常见的几种简单限流算法_常见的几种简单限流算法有哪些

temp10 2025-09-19 02:44:28 java教程 3 ℃ 0 评论

令牌桶算法(Token Bucket Algorithm)

令牌桶算法是一种基于速率限制的算法,其基本思想是将系统中的请求抽象成令牌,并以一定速度产生令牌放入桶中。每当有一个请求到达时,先从桶中获取一个令牌,如果没有令牌就表示请求被限流,否则就执行请求并从桶中取走一个令牌。

Java中可以使用Guava RateLimiter类来实现令牌桶算法。

常见的几种简单限流算法_常见的几种简单限流算法有哪些

//1秒钟产生10个令牌  100毫秒一个的速度匀速产生
RateLimiter rateLimiter = RateLimiter.create(10);
for (int i = 0; i < 50; i++) {
    //调用接口时获取令牌
    if (rateLimiter.tryAcquire(1)) {
    	System.out.println(i + " 拿到了");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    } else {
        //限流逻辑
        System.out.println(i + " 限流了");
    }
}

漏桶算法(Leaky Bucket Algorithm)

漏桶算法是一种基于速率限制的算法,其基本思想是将系统中的请求抽象成滴水,将滴水通过一个漏斗流出。漏斗的大小和水流速度都是固定的,当漏斗里的水满了之后,多余的水就会溢出,这时就表示请求被限流。

Java中可以使用Guava RateLimiter类来实现漏桶算法。

//1秒钟漏10滴  100毫秒一个的速度匀速漏出水滴
RateLimiter rateLimiter = RateLimiter.create(10);
for (int i = 0; i < 50; i++) {
    //放入时先尝试获取令牌
    if (rateLimiter.tryAcquire(1)) {
        System.out.println(i + " 成功时");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    } else {
         //限流逻辑
        System.out.println(i + " 失败了");
    }
}

计数器算法

计数器算法是一种基于计数的算法,其基本思想是在一定时间内统计请求的数量,当请求数量超过限制时就会触发限流。

Java中可以使用Redis类来实现计数器算法。

// 当前时间
long currentMs = System.currentTimeMillis();
// 窗口开始时间
long windowStartMs = currentMs - windowInSecond * 1000L;
// 按score统计key的value中的有效数量
Long count = redisTemplate.opsForZSet().count(key, windowStartMs, currentMs);
// 已访问次数 >= 最大可访问值
if (count >= limitPerSecond) {
    限流逻辑
}
 // 尝试对计数器进行 +1 操作
long count = jedis.incr(redisKey);

// 如果是第一次加入,则需要对键进行设置
if (count == 1) {
    jedis.expire(redisKey, 2); // 设置键的过期时间为2秒,即2秒内只能处理 limitPerSecond 个请求
}

// 如果计数器超过阈值则拒绝处理该请求
if (count > limitPerSecond) {
    // 限流逻辑
}


滑动窗口算法(Sliding Window Algorithm)

滑动窗口算法是一种基于时间窗口的算法,其基本思想是将时间分成若干个窗口,并对每个窗口内的请求进行计数,如果某个时间窗口内请求的数量超过限制,则触发限流。

Java中可以使用redis来实现滑动窗口算法。

//定义时间区间为1分钟
private final static int TIME_WINDOW = 60;
private final static String KEY_PREFIX = "req_count_"; //redis中的key前缀

private RedisTemplate redisTemplate;

public void limit(String id) {
    String key = KEY_PREFIX + id + "_" + System.currentTimeMillis() / 1000 / TIME_WINDOW;
    ValueOperations<String, String> ops = redisTemplate.opsForValue();
    if (!redisTemplate.hasKey(key)) {
        ops.set(key, "1");
        redisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);
    } else {
        int count = Integer.parseInt(ops.get(key));
        if (count < MAX_REQ) {
            ops.increment(key, 1);
        } else {
            //限流逻辑
        }
    }
}


漏斗算法(Funnel Algorithm)

漏斗算法是一种基于容量限制的算法,其基本思想是将系统中的所有请求加入到一个漏斗中,漏斗的流出速度固定,当漏斗中的请求超过容量限制时就会触发限流。需要注意与漏桶算法的区别,漏斗算法基于漏斗的原理,通过维护一个固定容量的消息队列,根据队列的当前状态决定是否允许新的请求或数据流入,从而达到控制流量的目的;漏桶算法则类似于一个漏桶,每次请求过来就相当于一滴水,水会根据固定的速率流入桶中,当桶满时,多余的水会被丢弃,从而达到平滑传输数据的效果。

Java中可以使用Guava RateLimiter类来实现漏斗算法。

// 动态调整速率,每秒钟随机流出10个请求
RateLimiter limiter = RateLimiter.create(10);

// 漏斗的容量为100,即请求最多可以积累100个
ArrayDeque<Integer> queue = new ArrayDeque<>(100);
for (int i = 0; i < 200; i++) {
    queue.offer(i);
    // 等待一定时间,模拟请求的间隔
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// 模拟用户请求
for (int i = 0; i < 200; i++) {
    // 尝试获取一个令牌,若获取到则处理该请求
    if (limiter.tryAcquire()) {
    	Integer request = queue.poll();
        if (request == null) {
            // 漏斗为空,限流
        } else {
             // 处理请求
        }
    } else {
        // 限流
    }

    // 等待一定时间,模拟请求的间隔
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表