Redis zset实现滑动窗口简单限流


/**
 * 计数器方法: 在10秒内,只有20个请求能访问我的代码
 * 实现方式: setnx key 10 value  每多一个请求,value就+1,,当value等于10时,不执行接下来的代码
 * 缺点: 能知道1-10s内有多少次请求,但是2-11s的请求数不知道
 * 时间滑动窗口
 * 下面介绍这种
 */
@AllArgsConstructor
public class RedisSimpleRateLimiter {

    private Jedis jedis;

    //无论返回什么,都表示用户已经点击过,通过这个方法,接下来的代码时要去判断该用户点击行为是否有效
    public boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) {
        String key = userId + ":" + actionKey;
        long now = System.currentTimeMillis();
        //大量操作一次性执行
        Pipeline pipeline = jedis.pipelined();
        pipeline.multi();
        pipeline.zadd(key, now, "" + now);//key , score , value
        //删除now-period*1000秒之前的数据(也就是说保留periods秒之内的数据)
        // 看清楚了这是直接删除了
        pipeline.zremrangeByScore(key, 0, now - period * 1000);
        //查看在period秒内用户点击了多少次(无效点击+有效点击都算在period秒之内,所以如果用户一直连续不断点击,会一直提示无效点击)
        //用户必须停下来等待几秒才可以,不能一直连续点击,前端可以做个计数器,一直点,后面的就不发请求了,过几秒再发
        Response<Long> count = pipeline.zcard(key);//返回count
        //这里给key设置过期时间,是防止冷用户占用内存
        pipeline.expire(key, period + 1);
        pipeline.exec();
        pipeline.close();
        //看看redis里面存的消息数量是不是小区我们限流的
        return count.get() <= maxCount;
    }

    public static void main(String[] args) throws InterruptedException {
        Jedis jedis = new RedisUtil().getJedis();
        RedisSimpleRateLimiter redisSimpleRateLimiter = new RedisSimpleRateLimiter(jedis);
        for (int x = 0; x < 15; x++) {
            System.out.println(redisSimpleRateLimiter.isActionAllowed("cixingrui", "reply", 10, 2));
            Thread.sleep(1000l);
        }
    }

}

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值