漏桶算法
漏桶算法是一种简单而常用的限流算法,它的基本思路是在一段时间内,将请求按照一定速率放入固定容量的桶中,如果桶已经满了,那么多余的请求就被丢弃。这个桶类似于一个漏桶,请求就像水一样按照一定的速率流入,当桶满了之后,多余的请求就像水溢出漏桶一样被丢弃。Redis 的自增INCR 刚好可以做这样的漏桶,并且key的过期时间刚好可以作为时间阈值。
实现思路
1.使用 Redis 的 INCR 命令对计数器进行自增操作。
2.判断一定时间内计数器是否超过了阈值。
3.如果超过了阈值,则表示当前请求需要被限流,可以返回错误信息或者直接抛出异常。
4.如果没有超过阈值,则表示当前请求可以被处理,继续执行业务逻辑。
5.在每个请求处理结束后,根据业务需求选择是否需要将计数器进行重置
代码实现
下面是一个基于 Redis 的简单限流器的 Java 实现:
import redis.clients.jedis.Jedis;
public class RedisLimiter {
private final String key;
private final int limit;
private final int timeout;
public RedisLimiter(String key, int limit, int timeout) {
this.key = key;
this.limit = limit;
this.timeout = timeout;
}
public boolean allowRequest(Jedis jedis) {
// 获取当前时间
long now = System.currentTimeMillis();
// 在 Redis 中设置计数器的 key
String counterKey = String.format("%s:%d", key, now / 1000);
// 对计数器进行自增操作
long count = jedis.incr(counterKey);
// 设置计数器的过期时间
jedis.expire(counterKey, timeout);
// 判断计数器是否超过阈值
if (count > limit) {
return false;
}
return true;
}
}
这个限流器每秒可以处理 limit 个请求,如果超过了这个阈值,则当前请求需要被限流。该限流器使用 Redis 的 INCR 命令对计数器进行自增操作,并通过设置计数器的过期时间实现自动重置计数器的功能。可以通过以下代码来测试该限流器的功能:
import redis.clients.jedis.Jedis;
public class Main {
public static void main(String[] args) {
// 连接 Redis
Jedis jedis = new Jedis("localhost", 6379);
// 创建限流器
RedisLimiter limiter = new RedisLimiter("test-limiter", 10, 1);
// 模拟处理请求
for (int i = 1; i <= 15; i++) {
if (limiter.allowRequest(jedis)) {
System.out.println("Processing request #" + i);
} else {
System.out.println("Request #" + i + " is limited");
}
}
// 关闭 Redis 连接
jedis.close();
}
}