网站首页 > 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();
}
}
- 上一篇: 常用限流算法与Guava RateLimiter源码解析
- 下一篇:已经是最后一篇了
猜你喜欢
- 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)
本文暂时没有评论,来添加一个吧(●'◡'●)