@Slf4j
@Component
@AllArgsConstructor
public class SlidingWindowRedis {
private static final Long TIMESCOPE = 1000L;
private final RedisTemplate<String, Long> redisTemplate;
public boolean qps(String quene, int sendQps, int qpsRetry) {
if (sendQps <= 0) {
return true;
}
boolean flag = false;
try {
for (int i = 0; i < qpsRetry; i++) {
if (this.add(quene, sendQps)) {
flag = true;
log.debug("第{}次成功", i + 1);
break;
}
log.debug("第{}次尝试", i + 1);
TimeUnit.MILLISECONDS.sleep(10L + (1000L / sendQps));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return flag;
}
public boolean add(String queue, Integer size) {
Long currentTime = System.currentTimeMillis();
while (size(queue) > size) {
poll(queue);
}
if (size(queue).equals(size)) {
if (currentTime - peek(queue) >= TIMESCOPE) {
poll(queue);
return offer(queue, currentTime);
}
return false;
} else {
return offer(queue, currentTime);
}
}
/**
* 取出队首元素,并删除
*
* @param queue
* @return
*/
public Long poll(String queue) {
return redisTemplate.opsForList().leftPop(queue);
}
/**
* 取出队首元素,不删除
*
* @param queue
* @return
*/
private Long peek(String queue) {
List<Long> list = redisTemplate.opsForList()
.range(queue, 0, 0);
return Optional.ofNullable(list).orElse(new ArrayList<>()).isEmpty() ? 0L : list.get(0);
}
/**
* 获取队列大小
*
* @param queue
* @return
*/
private Integer size(String queue) {
return Optional.ofNullable(redisTemplate.opsForList().size(queue))
.map(m -> Integer.parseInt(m.toString())).orElse(0);
}
/**
* 入队列
*
* @param queue
* @param value
* @return
*/
private boolean offer(String queue, Long value) {
redisTemplate.opsForList().rightPush(queue, value);
return true;
}
}
使用redis实现简单的QPS限流
最新推荐文章于 2024-06-13 11:04:50 发布