在 Spring Cloud Gateway 中,提供了 Redis 分布式限流器的实现,具体直接看 《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.10) 之 RequestRateLimiterGatewayFilterFactory 请求限流》 的 「5.3 Redis Lua 脚本」 部分。
另外,Redisson 库中,也提供了 Redis 分布式限流的实现,不过需要使用 Pro 版本。
? 请用 Redis 和任意语言实现一段恶意登录保护的代码,限制 1 小时内每用户 Id 最多只能登录 5 次。
这个问题,关键点,就是每个用户,每 3600 秒,只能登陆 5 次。这么一想,其实就是一个如何使用 Redis 实现限流的问题。Redis 实现限流,一共有两种方案:
使用 zset 实现滑动窗口限流。代码如下:
public boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) { String key = String.format(""hist:%s:%s"", userId, actionKey); // 使用用户编号 + 行为作为 KEY 。这样,我们就可以统计某个用户的操作行为。 long nowTs = System.currentTimeMillis(); // 获取当前时间。 Pipeline pipe = jedis.pipelined(); // pipeline 批量操作,提升效率。 pipe.multi(); // 此处启动了事务,可以保证指令的原子性。 pipe.zadd(key, nowTs, """" + nowTs); // zset 添加,key value score 要看下。 pipe.zremrangeByScore(key, 0, nowTs - (period * 1000)); // zremrangeByScore ,移除超过周期的 value 。 Response<Long> count = pipe.zcard(key); // zcard ,计算 zset 的数量 pipe.expire(key, period + 1); // 设置过期。这里多 + 1 秒,为了防止网络延迟。 pipe.exec(); // pipeline 执行 pipe.close(); return count.get() <= maxCount; // 是否超过最大次数。 }
- 该实现会存在一个问题,可能一个无效的操作,也被记录到次数中。完美的话,可能需要基于 Lua 脚本实现。
- 另外,上述代码是每秒操作的时间,实际需要改成每 N 秒。比较简单,直接上手怼即可。
- 使用 Lua 脚本,实现令牌桶限流算法。具体可以看看 《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.10) 之 RequestRateLimiterGatewayFilterFactory 请求限流》 的源码解析。
- 使用 Lua 脚本,实现简单的滑动窗口。
本文来自投稿,不代表本站立场,如若转载,请注明出处:
跨文化对比分析视角值得深入探索。