- 主页 > 生活百科 > >
接口限流还不太明白? 这篇文章可以看懂!( 二 )
这里我们实现的就是每秒产生的速率加上一个桶容量 。但是如何实现呢?这里有几个问题 。 需要保存什么数据在redis中?当前桶的容量,最新的请求时间 以什么数据结构存储?因为是针对接口限流,每个接口的业务逻辑不同,对并发的处理也是不同,因此要细化到每个接口的限流,此时我们选用HashMap的结构,hashKey是接口的唯一id,可以是请求的uri,里面的分别存储当前桶的容量和最新的请求时间 。 如何计算需要放令牌?根据redis保存的上次的请求时间和当前时间比较,如果相差大于的产生令牌的时间(陈某实现的是1秒)则再次产生令牌,此时的桶容量为当前令牌+产生的令牌 如何保证redis的原子性?保证redis的原子性,使用lua脚本即可解决 。 有了上述的几个问题,便能很容易的实现 。开撸1、lua脚本如下:
local ratelimit_info = redis.pcall('HMGET',KEYS[1],'last_time','current_token')local last_time = ratelimit_info[1]local current_token = tonumber(ratelimit_info[2])local max_token = tonumber(ARGV[1])local token_rate = tonumber(ARGV[2])local current_time = tonumber(ARGV[3])if current_token == nil thencurrent_token = max_tokenlast_time = current_timeelselocal past_time = current_time-last_timeif past_time>1000 thencurrent_token = current_token+token_ratelast_time = current_timeend## 防止溢出if current_token>max_token thencurrent_token = max_tokenlast_time = current_timeendendlocal result = 0if(current_token>0) thenresult = 1current_token = current_token-1last_time = current_timeendredis.call('HMSET',KEYS[1],'last_time',last_time,'current_token',current_token)return result - 调用lua脚本出四个参数,分别是接口方法唯一id,桶容量,每秒产生令牌的数量,当前请求的时间戳 。
【接口限流还不太明白? 这篇文章可以看懂!】2、 SpringBoot代码实现
- 采用Spring-data-redis实现lua脚本的执行 。
- Redis序列化配置:
/*** 重新注入模板*/@Bean(value = https://www.isolves.com/it/cxkf/bk/2020-06-12/"redisTemplate")@Primarypublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplate template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);ObjectMApper objectMapper = new ObjectMapper();objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//设置序列化方式,key设置string 方式,value设置成jsonStringRedisSerializer stringRedisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);jsonRedisSerializer.setObjectMapper(objectMapper);template.setEnableDefaultSerializer(false);template.setKeySerializer(stringRedisSerializer);template.setHashKeySerializer(stringRedisSerializer);template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);return template;}/** * @Description 限流工具类 * @Author CJB * @Date 2020/3/19 17:21 */public class RedisLimiterUtils {private static StringRedisTemplate stringRedisTemplate=ApplicationContextUtils.applicationContext.getBean(StringRedisTemplate.class);/*** lua脚本,限流*/private final static String TEXT="local ratelimit_info = redis.pcall('HMGET',KEYS[1],'last_time','current_token')n" +"local last_time = ratelimit_info[1]n" +"local current_token = tonumber(ratelimit_info[2])n" +"local max_token = tonumber(ARGV[1])n" +"local token_rate = tonumber(ARGV[2])n" +"local current_time = tonumber(ARGV[3])n" +"if current_token == nil thenn" +"current_token = max_tokenn" +"last_time = current_timen" +"elsen" +"local past_time = current_time-last_timen" +"n" +"if past_time>1000 thenn" +"tcurrent_token = current_token+token_raten" +"tlast_time = current_timen" +"endn" +"n" +"if current_token>max_token thenn" +"current_token = max_tokenn" +"tlast_time = current_timen" +"endn" +"endn" +"n" +"local result = 0n" +"if(current_token>0) thenn" +"result = 1n" +"current_token = current_token-1n" +"last_time = current_timen" +"endn" +"redis.call('HMSET',KEYS[1],'last_time',last_time,'current_token',current_token)n" +"return result";/*** 获取令牌* @param key 请求id* @param max 最大能同时承受多少的并发(桶容量)* @param rate每秒生成多少的令牌* @return 获取令牌返回true,没有获取返回false*/public static boolean tryAcquire(String key, int max,int rate) {List<String> keyList = new ArrayList<>(1);keyList.add(key);DefaultRedisScript<Long> script = new DefaultRedisScript<>();script.setResultType(Long.class);script.setScriptText(TEXT);return Long.valueOf(1).equals(stringRedisTemplate.execute(script,keyList,Integer.toString(max), Integer.toString(rate),Long.toString(System.currentTimeMillis())));}}
推荐阅读
-
金融期货|中国金融期货交易所招聘2023年应届毕业生、博士后,12月18日前报名
-
肖战|肖战新剧为何广受欢迎?看戏里戏外,都是跨越年龄的吸引力!
-
每日搭配指南|简约优雅不失高级感,值得收藏!,30+女人秋季气质穿搭示范
-
#美味跳动餐料调料#夏季太热无心下厨房?幸亏屯了这些方便食品
-
-
运势|八月中旬,事业红火,运势走高,赚足财帛,苦难熬完的属相
-
游龙战神|76.39 亿!高通担心的终于成真!联发科正成为市场“新宠”
-
张继科|张继科事件继续升级,牵扯借钱明星达到5位,张继科本人终于回应
-
「中新网」土耳其将因在叙军事行动被赶出北约?美媒:不太可能
-
次元快讯|为自己摘果庆生,网友:只可远观,不可细看!,杨丽萍59岁大寿
-
上观新闻|推动“夜游”和“沉浸式”文旅消费,南京路步行街又有新玩法
-
-
[萨拉赫]利物浦巨星不得了!年收入暴涨7300万 从第12飙升到第4
-
枣庄在线|九斤超重宝宝在枣矿中心医院成功顺产!为妈妈和宝宝鼓掌
-
体育大亨▲美容养颜、滋润肌肤,身体棒棒哒!,适合女性吃的3种食物
-
【新华社】看美丽乡村 庆70华诞丨江苏省苏州市吴中区临湖镇灵湖
-
证券日报|天山生物12天飙涨494.51% 谁能驱赶“疯牛”心中的“魔”?
-
背心|潮流的针织背心裙又火了,时髦经典,内搭衬衫就足够好看
-
网红白冰直播首秀被骂哭!大量网友质疑他搞分裂,曝更多细节内幕
-
银行|超预期!6月份结构性存款压降1.01万亿,产品"量价齐跌",套利空间还有多大?