一、Redis-Cell安装如下
CL.THROTTLE user123 15 30 60 1
三、返回值
127.0.0.1:6379> CL.THROTTLE user123 15 30 60 1) (integer) 0 # 0允许,1拒绝 2) (integer) 16 # 容量,等于指令第二个参数 +1 3) (integer) 15 # 剩余量 4) (integer) -1 #-1表示正常放入,0表示已满,正数表示几秒可放入(单位:秒) 5) (integer) 2 # 多长时间漏斗完全漏空(单位:秒)
四、spring boot代码
package com.zyweb.admin.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
* @Author ZhangYi
*/
@Component
public class RedisUtil {
private final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* lua 脚本
*/
public static final String LUA_SCRIPT = "return redis.call('cl.throttle',KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4])";
/**
* 测试
*
* @param key
* @param maxBurst
* @param countPerPeriod
* @param period
* @param quantity
* @return
*/
public boolean redisCellDemo(String key, int maxBurst, int countPerPeriod, int period, int quantity) {
try {
DefaultRedisScript<List> script = new DefaultRedisScript<>(LUA_SCRIPT, List.class);
/**
* KEYS[1]需要设置的key值,可以结合业务需要
* ARGV[1]参数是漏斗的大小 最大爆发
* ARGV[2]频率次数,结合ARGV[3]一起使用
* ARGV[3]周期(秒),结合ARGV[2]一起使用
* 最后的速率就是ARGV[2]次/ARGV[3]秒
* ARGV[4]申请令牌数,默认是1
*/
List<Long> rst = redisTemplate.execute(script, Arrays.asList(key), maxBurst, countPerPeriod, period, quantity);
logger.info("限流{}返回:{}", key, rst);
/**
* 1. 动作是否受限:
* 0 表示允许该操作。
* 1 表示该操作受到限制/阻止。
* 2. 密钥的总限制 (max_burst+1)。这相当于常见的X-RateLimit-Limit HTTP返回头。
* 3. 密钥的剩余限制。相当于X-RateLimit-Remaining。
* 4. 用户应重试之前的秒数,-1如果允许操作,则始终如此。相当于Retry-After。
* 5. 限制将重置为其最大容量之前的秒数。相当于X-RateLimit-Reset。
*/
//这里只关注第一个元素0表示正常,1表示过载
return rst.get(0) == 0;
} catch (Exception e) {
logger.error("限流{}获取抛错:", key, e);
return false;
}
}
}
五、测试
@GetMapping("/redisCell")
public void redisCell(){
// 模拟30次请求
for (int i = 0; i < 30; i++) {
boolean rst = redisUtil.redisCellDemo("user123 ", 5, 10, 30, 1);
if (!rst) {
logger.info("访问{}过于频繁,请稍后再试",i);
} else {
logger.info("访问{}通过",i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
六、demo表示,每秒有1个请求进入,漏斗最大容量为5,漏水速率为10个/30秒,也就是3秒钟漏掉一个