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;
}
网友评论