Redis 可以通过以下几种方式实现限流:
- 使用 Redis 的命令时间戳实现简单限流:
- 在一定时间窗口内,同一个键只允许执行指定次数的命令。
- 如果超过限定次数,则返回错误信息拒绝请求。
例如:
// 前5秒钟内同一个用户最多执行10次命令
if (jedis.commandTypeName("some_key").getTimestamp() > System.currentTimeMillis() - 5000 &&
jedis.commandTypeName("some_key").getCount() > 10) {
return jedis.commandTypeName("some_key").error("User exceed request limit");
}
- 使用 HyperLogLog 统计用户操作次数,并设置最大操作阈值实现限流:
例如:
// 用户操作计数器,前5秒最多20次
Jedis jedis = new Jedis("localhost");
String hllKey = "user:hll:counter";
if (jedis.pfCount(hllKey) > 20 && jedis.pfAdd(hllKey, "user_id") > 1) {
return "User exceed request limit";
}
jedis.pexpire(hllKey, 5000); // 5秒过期
- 使用 Redis 的发布订阅模式限制用户操作频率:
- 用户操作时向频道名为用户ID的频道发布消息。
- 一个监听者监听所有用户频道,统计短时间内每个频道接收到的消息条数。
- 如果某频道消息超过限定数量,则拒绝用户请求。
例如:
// 监听者
jedis.subscribe(new JedisPubSub() {
public void onMessage(String channel, String message) {
int count = counts.getOrDefault(channel, 0) + 1;
counts.put(channel, count);
if (count > 20) { // 20秒内超过20条信息,拒绝请求
jedis.publish(channel, "reject");
}
}
}, "user:*"); // 监听所有用户频道
// 用户操作发布消息
jedis.publish("user:1", "command");