redis+lua+拦截器实现限流

前言

当非法用户死命调用你的接口(机器攻击)时,怎么办?
正常情况下,用户是不会那么频繁的通过前端调用你的接口的。一般出现某个用户极其频繁的调用你的接口时,那就一定要小心了,可能是想搞你!!!所以,一定要在API调用前端加个限流策略,也就是将用户的一段时间的访问次数记下来,超过某个值的时候,拒绝其访问。这种限流,可以加在nginx里面,也可以加在项目的过滤器中。
但是这种高频数据放在哪呢?数据库?那你的数据库可能直接就炸了!!!ok,还是放在redis里吧!这时候就要考虑操作的原子性了。
今天用lua来实现这个功能!

实现

lua实现的限流脚本

-- ip限流脚本
-- 限定每个ip在expire_time时间段内只能访问limit次
-- 脚本返回0,说明已到达上限,返回1,说明没有到达上限

local ip = KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2]

local exist = redis.call('exists', ip)
if exist == 1 then
    if redis.call('incr', ip) > limit then
        return 0
    else
        return 1
    end
else
    redis.call('set', ip, 1);
    redis.call('expire', ip, expire_time)
    return 1
end

实现一个限流处理器

package com.zyu.boot.demo.utils.limit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * redis实现IP限流器
 */
@Component
public class IPLimiter {
   

    private RedisTemplate redisTemplate;
    /**
     * 每个流控周期允许访问的次数
     */
    private final int limit = 5;
    /**
     * 流控的时间段:秒
     */
    private final int expire = 2;
    /**
     * 限流的脚本
     */
    private final String LIMITER_SCRIPT_PATH = "lua/ipLimiter.lua";

    private DefaultRedisScript<Boolean> limiterScript;

    public IPLimiter(@Autowired RedisTemplate redisTemplate) {
   
        this.redisTemplate = redisTemplate;
        limiterScript = new DefaultRedisScript();
        limiterScript.setLocation(new ClassPathResource(LIMITER_SCRIPT_PATH));
        limiterScript.setResultType(Boolean.class);
    }

    /**
     * 返回true表示未触发流控,false表示触发流控
     *
     * @param ip
     * @return
     */
    public boolean limiterValidate(String ip) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值