网站首页 > java教程 正文
令牌桶算法(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();
    }
}
    
猜你喜欢
- 2025-09-19 常用限流算法与Guava RateLimiter源码解析
 - 2025-09-19 如何实现一个简单可行的限流方法,保障电商系统的稳定性
 - 2025-09-19 常见的4种限流算法与实现_限流方法原理
 - 2025-09-19 API能力开放平台设计思路剖析_开放api技术
 - 2025-09-19 Sentinel 是什么?它是如何实现限流的?
 - 2025-09-19 限流算法面面观:Sentinel与Gateway的差异揭秘
 - 2025-09-19 在Spring Boot集成Bucket4j实现接口限流操作
 - 2025-09-19 Spring Boot3 中实现单节点限流操作全解析
 - 2025-09-19 一文搞懂!7种常见的限流方式!_限流的几种方式
 - 2025-09-19 Java API Gateway动态限流,流量控制还能这么玩?一线实战全解析!
 
欢迎 你 发表评论:
- 最近发表
 
- 标签列表
 - 
- java反编译工具 (77)
 - java反射 (57)
 - java接口 (61)
 - java随机数 (63)
 - java7下载 (59)
 - java数据结构 (61)
 - java 三目运算符 (65)
 - java对象转map (63)
 - Java继承 (69)
 - java字符串替换 (60)
 - 快速排序java (59)
 - java并发编程 (58)
 - java api文档 (60)
 - centos安装java (57)
 - java调用webservice接口 (61)
 - java深拷贝 (61)
 - 工厂模式java (59)
 - java代理模式 (59)
 - java.lang (57)
 - java连接mysql数据库 (67)
 - java重载 (68)
 - java 循环语句 (66)
 - java反序列化 (58)
 - java时间函数 (60)
 - java是值传递还是引用传递 (62)
 
 

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