美文网首页
基于Redis的简单限流

基于Redis的简单限流

作者: Mick米壳 | 来源:发表于2019-04-07 19:27 被阅读0次

    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;
        }
    

    相关文章

      网友评论

          本文标题:基于Redis的简单限流

          本文链接:https://www.haomeiwen.com/subject/vtfeiqtx.html