基于Redis的简单限流

2019-04-07  本文已影响0人  Mick米壳

BUCKET_MONITOR:保存过去{timeout}时间内的请求
BUCKET_COUNT:用于记录请求的顺序。每到达一个请求,该计数器+1
BUCKET:保留过去{timeout}时间内的成功请求

            //获取UUID
            String token = UUID.randomUUID().toString();
            long now = System.currentTimeMillis();
            //开启事务
            Transaction transaction = jedis.multi();

            //删除BUCKET_MONITOR中{timeout}时间之前的请求
transaction.zremrangeByScore((BUCKET_MONITOR + point).getBytes(), "-inf".getBytes(), String.valueOf(now - timeout).getBytes());
            //zinterstore的权重因子,使BUCKET中的score为原来的类型(即BUCKET_COUNT)
            ZParams params = new ZParams();
            params.weightsByDouble(1.0, 0.0);
            //计算交集,清除BUCKET中的过时请求,这些请求将不被考虑
            transaction.zinterstore(BUCKET + point, params, BUCKET + point, BUCKET_MONITOR + point);

            //计数器自增,记录到达的请求数
            transaction.incr(BUCKET_COUNT);
            List<Object> results = transaction.exec();
            long counter = (Long) results.get(results.size() - 1);

            //新建一个事务
            transaction = jedis.multi();
            //向两个BUCKET中添加内容,score分别为请求到达的时间和BUCKET_COUNT
            transaction.zadd(BUCKET_MONITOR + point, now, token);
            transaction.zadd(BUCKET + point, counter, token);
            transaction.zrank(BUCKET + point, token);
            results = transaction.exec();
            //获取排名(小->大),判断请求是否取得了信号量(也即是否队伍长度超限)
            long rank = (Long) results.get(results.size() - 1);
            if (rank < limit) {
                return token;
            } else {
                //没有获取到信号量,清理之前放入redis中垃圾数据
                transaction = jedis.multi();
                //Zrem移除刚才加入的score
                transaction.zrem(BUCKET_MONITOR + point, token);
                transaction.zrem(BUCKET + point, token);
                transaction.exec();
            }
        } catch (Exception e) {
            log.error("限流出错" + e.toString());
        }
        return null;
    }
上一篇下一篇

猜你喜欢

热点阅读