使用Redis进行接口限流

流程图

代码实现

/**
 * 是否限制接口请求
 *
 * @param request 请求体
 * @return true-禁止请求 false-允许请求
 */
private boolean limitApi(HttpServletRequest request) {
    String uri = request.getRequestURI();
    String ip = request.getRemoteAddr();
    String key = "limit:" + uri + ":" + ip;

    // 30秒内限制10次访问
    long limit = 10L;
    long timeout = 30L;

    boolean b = RedisUtils.setNX(key, 1, timeout, TimeUnit.SECONDS);
    if (b) {
        log.info("1时间范围内第一次访问,允许");
        return false;
    } else {
        Object result = RedisUtils.getString(key);
        if (result == null) {
            RedisUtils.setNX(key, 1, timeout, TimeUnit.SECONDS);
            log.info("2时间范围内第一次访问,允许");
            return false;
        } else {
            long count = Long.parseLong(String.valueOf(result));
            if (count >= limit) {
                log.error("时间范围内请求次数过多, 已经请求次数:{},不允许访问", count + 1);
                return true;
            } else {
                RedisUtils.increment(key);
                log.info("请求次数符合限制, 已经请求次数:{},允许", count + 1);
                return false;
            }
        }
    }
}

注意点

  1. Redis increment 操作要使用 StringRedisTemplate,否则会出现操作异常;
  2. 最好使用 Lua 脚本操作,避免 Redis 的多次连接,保证原子性和性能;

附:Lua脚本

把限制逻辑封装到一个Lua脚本中,调用时只需传入:key、限制数量、过期时间,调用结果就会指明是否运行访问

local notexists = redis.call(\"set\", KEYS[1], 1, \"NX\", \"EX\", tonumber(ARGV[2]))
if (notexists) then
  return 1
end
local current = tonumber(redis.call(\"get\", KEYS[1]))
if (current == nil) then
  local result = redis.call(\"incr\", KEYS[1])
  redis.call(\"expire\", KEYS[1], tonumber(ARGV[2]))
  return result
end
if (current >= tonumber(ARGV[1])) then
  error(\"too many requests\")
end
local result = redis.call(\"incr\", KEYS[1])
return result

使用 eval 调用

eval 脚本 1 key 参数-允许的最大次数 参数-过期时间

参考:https://www.cnblogs.com/duhuo/p/5002319.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值