redis 基于时间窗口的限流

    /**
     * redis 基于时间滑动窗口,进行限流逻辑
     *
     * @param actionKeyEnum 动作标记的限流,比如秒杀seckill
     * @param keyParam      业务的唯一标识
     * @param period        限流的频率  多少秒内进行限流
     * @param maxCount      最大限流数量
     */
public boolean limitRateActionAllowed(LimitRateActionEnum actionKeyEnum, String keyParam, int period, int maxCount) {
        // 生成唯一的key
        actionKeyEnum = actionKeyEnum == null ? LimitRateActionEnum.GENERATOR : actionKeyEnum;
        keyParam = StringUtils.isEmpty(keyParam) ? "0" : keyParam;


        String key = String.format(RedisKeyCnst.LIMIT_RATE, actionKeyEnum.getName(), keyParam);
        long nowTs = System.currentTimeMillis();
        // 一定要确保唯一,纳秒时间都有可能会导致不唯一
        String uuid = UUID.randomUUID().toString();

        RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
        // 使用管道
        List<Object> executeResultList = stringRedisTemplate.executePipelined((RedisCallback<Long>) connection -> {
            //stringRedisTemplate.executePipelined((RedisCallback<Long>) connection -> {
            connection.multi();

            // 添加当前操作当zset中
            connection.zAdd(serializer.serialize(key), nowTs, serializer.serialize(uuid));

            // 整理zset,删除时间窗口外的数据, 删除 0 到 nowTs - period * 1000 之间的数据, 返回删除的数量
            connection.zRemRangeByScore(serializer.serialize(key), 0, nowTs - period * 1000);

            //当前存在的数量: 可以认为是流量数量
            Long count = connection.zCard(serializer.serialize(key));

            //重新设置key的过期时间
            connection.expire(serializer.serialize(key), period + 1);

            connection.exec();
            connection.close();
            return null;
        }, stringRedisTemplate.getValueSerializer());

        Integer count = 0;

        // [[true,0,6,true]]
        //true: zAdd的执行结果 ,
        // 0:zRemRangeByScore的执行结果,本次已删除的数量,
        // 6:count的执行结果,当前流量总数,
        // true: 设置key的过期时间
        //String executeResultListStr = JSONObject.toJSONString(executeResultList);
        //System.out.println(executeResultListStr);
        log.info("基于时间滑动窗口,进行限流结果:{}", JSONObject.toJSONString(executeResultList));
        Object exeResultList = executeResultList.get(0);
        JSONArray resultSingleList = JSONObject.parseArray(JSONObject.toJSONString(exeResultList));
        count = (Integer) resultSingleList.get(2);

        return count <= maxCount;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值