最新要闻
- 焦点快报!深赛格:融资净买入132.4万元,融资余额1.03亿元(04-04)
- 天天报道:中国为何未研制出ChatGPT?中科院包云岗:需要优秀技术团队、雄厚资金
- 苏炳添用iPhone 14引热议 本人回应:与小米合约到期 手机摔坏才换
- 大妈捡手机要好处费2包烟见面变500元被吐槽:你捡到会痛快归还吗?
- 焦点速读:NV不愁卖!2023年PC游戏硬件市场继续萎缩:AMD、Intel显卡要打对折卖
- 天天最资讯丨核污水将倒入大海 降低水产品辐射分析精度!日本1.8亿粒扇贝不明原因死亡
- 世界快看:64位才是王道!《英雄联盟》13.7版本今日更新:32位Win系统续一条命
- 汽车仪表盘显示感叹号加个圆圈_汽车仪表盘显示感叹号
- 世界热文:海盗船192GB DDR5内存套装开卖:带上“光污染” 7699元!
- 天天百事通!研究了2600多篇爆仓文学后 我好像搞懂人是怎么变赌狗的了
- 天天看点:无数人的童年回忆:重制后把我裤子都感动湿了
- 标准版也要有高刷了!iPhone全系列或于2025年引入LTPO技术
- 【环球时快讯】穿越之汉武帝
- 世界微速讯:彻底崩了!AI遭全球“围剿” A股咋应对?超9000人联名“封杀” 巴菲特又要“抄底”?
- 【当前热闻】房东称闰二月要多交1个月房租 网友:这是住在月亮上吗?
- ChatGPT需要1万张NVIDIA A100显卡 国内仅有6家公司做到
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
SpringBoot如何进行限流,老鸟们还可以这样玩!
大家好,我是飘渺。
在SpringBoot 如何进行限流,老鸟们都这么玩的!一文中我们详细介绍了为什么需要对接口进行限流,也介绍了常见的限流算法,最后还基于Guava工具类实现了接口限流。但是这种方式有个问题,无法实现分布式限流。那今天我们来利用Redis + Lua 来实现分布式限流。
(资料图片仅供参考)
Lua 脚本和 MySQL 数据库的存储过程比较相似,他们执行一组命令,所有命令的执行要么全部成功或者失败,以此达到原子性。也可以把 Lua 脚本理解为,一段具有业务逻辑的代码块。
实现过程
第一步:引入Redis依赖包
org.springframework.boot spring-boot-starter-data-redis
第二步:配置Redis
/** * @author JAVA日知录 * @date 2022/5/2 22:35 */@Configurationpublic class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式) Jackson2JsonRedisSerializer
第二步:自定义限流注解
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})@Documentedpublic @interface RedisLimit { /** * 资源的key,唯一 * 作用:不同的接口,不同的流量控制 */ String key() default ""; /** * 最多的访问限制次数 */ long permitsPerSecond() default 2; /** * 过期时间也可以理解为单位时间,单位秒,默认60 */ long expire() default 60; /** * 得不到令牌的提示语 */ String msg() default "系统繁忙,请稍后再试.";}
第三步:创建限流异常
/** * @author JAVA日知录 * Redis限流自定义异常 * @date 2022/5/2 21:43 */public class RedisLimitException extends RuntimeException{ public RedisLimitException(String msg) { super( msg ); }}
第四步:使用AOP切面拦截限流注解
/** * Limit AOP * @author JAVA日知录 * @date 2021/9/24 3:07 下午 */@Slf4j@Aspect@Componentpublic class RedisLimitAop { @Autowired private StringRedisTemplate stringRedisTemplate; @Pointcut("@annotation(com.jianzh5.blog.limit.redis.RedisLimit)") private void check() { } @Before("check()") public void before(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); //拿到RedisLimit注解,如果存在则说明需要限流 RedisLimit redisLimit = method.getAnnotation(RedisLimit.class); if(redisLimit != null){ //获取redis的key String key = redisLimit.key(); String className = method.getDeclaringClass().getName(); String name = method.getName(); String limitKey = key + className + method.getName(); log.info(limitKey); if(StringUtils.isEmpty(key)){ throw new RedisLimitException( "key cannot be null" ); } long limit = redisLimit.permitsPerSecond(); long expire = redisLimit.expire(); List keys = new ArrayList<>(); keys.add( key ); String luaScript = buildLuaScript(); RedisScript redisScript = new DefaultRedisScript<>( luaScript, Long.class ); Long count = stringRedisTemplate.execute( redisScript, keys, String.valueOf(limit), String.valueOf(expire) ); log.info( "Access try count is {} for key={}", count, key ); if (count != null && count == 0) { log.debug("令牌桶={},获取令牌失败",key); throw new RedisLimitException(redisLimit.msg()); } } } /** * 构建redis lua脚本 * @return */ private String buildLuaScript() { StringBuilder luaString = new StringBuilder(); luaString.append( "local key = KEYS[1]" ); //获取ARGV内参数Limit luaString.append( "\nlocal limit = tonumber(ARGV[1])" ); //获取key的次数 luaString.append( "\nlocal curentLimit = tonumber(redis.call("get", key) or \"0\")" ); luaString.append( "\nif curentLimit + 1 > limit then" ); luaString.append( "\nreturn 0" ); luaString.append( "\nelse" ); //自增长 1 luaString.append( "\n redis.call(\"INCRBY\", key, 1)" ); //设置过期时间 luaString.append( "\nredis.call(\"EXPIRE\", key, ARGV[2])" ); luaString.append( "\nreturn curentLimit + 1" ); luaString.append( "\nend" ); return luaString.toString(); }}
第五步:给需要限流的接口加上注解
/** * 公众号:JAVA日知录 * 限流测试类基于Redis限流 */@Slf4j@RestController@RequestMapping("/limit/redis")public class LimitRedisController { /** * 基于Redis AOP限流 */ @GetMapping("/test") @RedisLimit(key = "redis-limit:test", permitsPerSecond = 2, expire = 1, msg = "当前排队人数较多,请稍后再试!") public String test() { log.info("限流成功。。。"); return "ok"; }}
第六步:体验效果
通过访问测试地址: http://127.0.0.1:8080/limit/redis/test,反复刷新并观察输出结果:
正常响应时:
{"status":100,"message":"操作成功","data":"ok","timestamp":1652343229643}
触发限流时:
{"status":500,"message":"当前排队人数较多,请稍后再试!","data":null,"timestamp":1652343239035}
通过观察得之,基于自定义注解同样实现了接口限流的效果。
优化
程序每次执行每次都需要通过buildLuaScript()
方法构建lua执行脚本,比较 low,我们可以生成一个lua文件放在resources目录下,利用@PostConstruct
注解提前加载。
- 在resouces文件夹下创建lua文件 rateLimiter.lua
--获取KEYlocal key = KEYS[1]local limit = tonumber(ARGV[1])local curentLimit = tonumber(redis.call("get", key) or "0")if curentLimit + 1 > limit then return 0else -- 自增长 1 redis.call("INCRBY", key, 1) -- 设置过期时间 redis.call("EXPIRE", key, ARGV[2]) return curentLimit + 1end
- 修改RedisLimitAop,通过@PostConstruct注入DefaultRedisScript
@Slf4j@Aspect@Componentpublic class RedisLimitAop { @Autowired private StringRedisTemplate stringRedisTemplate; private DefaultRedisScript redisScript; @PostConstruct public void init(){ redisScript = new DefaultRedisScript<>(); redisScript.setResultType(Long.class); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua"))); } ...}
小结
基于Redis + Lua 可以很方便地实现分布式限流,算是SpringBoot老鸟系列限流文章的补充扩展。
那么现在问题来了,我们现在有基于Guava实现的单机限流,又有基于Redis+Lua实现的分布式限流,那能不能将两种限流功能做成一个独立的公共组件,让使用方根据实际情况选择对应的限流功能呢?
老鸟系列源码已经上传至GitHub,需要的在公号【JAVA日知录】回复关键字 0923获取源码地址。
关键词:
SpringBoot如何进行限流,老鸟们还可以这样玩!
环球微资讯!Podman Compose 新手指南
环球今热点:美国ADP就业数据不及预期 暗示劳动力需求降温
焦点快报!深赛格:融资净买入132.4万元,融资余额1.03亿元(04-04)
天天报道:中国为何未研制出ChatGPT?中科院包云岗:需要优秀技术团队、雄厚资金
苏炳添用iPhone 14引热议 本人回应:与小米合约到期 手机摔坏才换
大妈捡手机要好处费2包烟见面变500元被吐槽:你捡到会痛快归还吗?
焦点速读:NV不愁卖!2023年PC游戏硬件市场继续萎缩:AMD、Intel显卡要打对折卖
每日资讯:沪广深去年公积金个贷降两成 今年超60地优化公积金政策
天天速递!科技伦理审查提速 AI“变坏”设防
天天最资讯丨核污水将倒入大海 降低水产品辐射分析精度!日本1.8亿粒扇贝不明原因死亡
世界快看:64位才是王道!《英雄联盟》13.7版本今日更新:32位Win系统续一条命
汽车仪表盘显示感叹号加个圆圈_汽车仪表盘显示感叹号
【天天报资讯】读SQL进阶教程笔记10_HAVING下
Python 开发环境安装
世界热文:海盗船192GB DDR5内存套装开卖:带上“光污染” 7699元!
天天百事通!研究了2600多篇爆仓文学后 我好像搞懂人是怎么变赌狗的了
天天看点:无数人的童年回忆:重制后把我裤子都感动湿了
标准版也要有高刷了!iPhone全系列或于2025年引入LTPO技术
【环球时快讯】穿越之汉武帝
世界微速讯:彻底崩了!AI遭全球“围剿” A股咋应对?超9000人联名“封杀” 巴菲特又要“抄底”?
【打怪升级】【jvm】关于jvm内存模型及GC调优
【当前热闻】房东称闰二月要多交1个月房租 网友:这是住在月亮上吗?
ChatGPT需要1万张NVIDIA A100显卡 国内仅有6家公司做到
全球快消息!杭州一男子坐地铁自带沙发 怎么过的安检?地铁回应
焦点热讯:Lambda
TVM Deploy Runtime[施工中]
环球精选!股债二八平衡策略
世界实时:20年来最优秀游戏处理器!AMD锐龙7 7800X3D首发评测:大幅超越i9-13900KS
周鸿祎离婚给前妻90亿 李国庆羡慕:没争夺控制权 他就乐吧
RTX 3060登顶Steam神卡 AMD显卡被黑?竟是国内玩家的锅
全球快资讯丨“索要千万逼死老公案”五年后一审宣判:妻子翟欣欣退还男方上千万财产
环球热头条丨我的第一个项目(九) :飞机大战Vue版本塞到主页
Unity开发Hololens2—环境配置
设计模式(三十二)----综合应用-自定义Spring框架-自定义Spring IOC-自定义Spring IOC总结
CS50-Python实验3,4
天天精选!00后都开始立遗嘱了:微信号、QQ号、游戏账号成热门虚拟财产
《他是谁》烂尾 编剧疑似甩锅剧本总监:感谢你把剧本改成这
世界快讯:莱万:若留拜仁或会失去踢球的乐趣 在巴萨除了进球我有不同角色
【全球热闻】上映25周年纪念!《泰坦尼克号》4K重映版票房破2000万
每日热点:全球首例真人状告机器人!澳大利亚一市长准备告ChatGPT诽谤
Cesium 案例(二)Web MapTile Service with Time
渗透测试——简单的流程化信息收集
胖东来创始人称加班不道德:不能只挣钱
世界热头条丨在Steam上买了个假冒黄游 结果居然给我玩爽了
焦点热文:女子称使用化妆品后流产 送检发现:汞含量超标30万倍!
每日消息!俄罗斯一男子19楼坠落后自行上救护车:还给医务人员唱了歌
全球热文:速速电影院-尽情泡约网电影院
索尼推出WF-C700N无线耳机:15小时长续航、支持空间音频
GT2大探成最后一款!真我手机将不再有“大师探索版”
福布斯发布2023亿万富豪榜:亚马逊贝索斯最惨 资产流失近4000亿
焦点播报:AOC公布小苔藓M6迷你主机:i5-13420H、配全功能USB-C
101岁杨振宁罕见露面 获香港大学名誉博士学位
天天热门:java字节流和字符流
如何设计一个 70w 在线人数的弹幕系统 ?
vivo X Fold2通过3C认证:4800mAh电池+120W快充
当前快播:比尔盖茨回应暂停训练AI:并不能解决问题 重点是最大程度利用
今日最新!告别Mini LED!MacBook Pro屏幕将升级为OLED:三星供货
回国在即!旅美熊猫丫丫上海检疫后将被北京动物园接走
每日热文:汇编第三章复习之七种寻址
请注意!武汉全民健身中心游泳馆营业时间调整
199元一人!金山办公推出WPS 365“全家桶”服务
最资讯丨飞利浦推出新款44.5寸带鱼屏:弹出式摄像头 售价近9000元
头条焦点:真人电影《芭比》新预告:小丑女尽显修长美腿
女子请假照顾病危丈夫被公司开除!法院判了:公司赔13万
世界热议:sms-activate操作简便易上手且好用的接码工具【保姆级教程】
环球新消息丨5岁娃上坟藏冥币带回家要送朋友:还有男孩在奶奶坟前跪求不写作业不挨打
新势力老大换了!理想汽车周交付超6000辆:超蔚来、小鹏总和
环球热点评!2023年清明档票房破亿!任天堂《超级马力欧兄弟大电影》暂列亚军
天天热消息:立省4万!商家上线理想L7、L8“激光雷达”改装件:自己都能装
全球观天下!李子柒油管广告收益登顶热搜 停更一年收入78万元
世界热讯:宿迁贷款利率2022最新利率表,宿迁贷款利息
沙特俄罗斯等减产拉高油价后 黄金大涨近2%逼近历史最高纪录:美国难受
焦点速读:豆瓣8.0分!电影《忠犬八公》票房破亿:冯小刚主演
自建堆排序:
焦点!JavaScript快速入门(二)
微头条丨你坐过吗?这款双层火车全国仅此一列
焦点快播:必看?迪士尼《小美人鱼》内地定档5月26日 最新剧照黑小美人鱼亮相
全球热讯:时隔6年 任天堂马里奥之父宫本茂暗示新作要来了:告别手游平台
特斯拉法务部要玩真的了 马斯克:我们找了许多有才的律师
环球视点!666元起!国内一公司推出太空葬 创始人:逝去亲人快到头顶会手机提醒
福布斯发布2023亿万富豪榜 全球新首富诞生:要把股份平均分给五个子女
法拉利F1车手莱克莱尔签名时200万名表被抢走 小偷今落网
民主失真、政治失能严重侵蚀美式人权根基(钟声)——美国已成为全球人权发展的搅局者和阻碍者④
【独家】虚拟机磁盘扩容(parted、lvm)
环球今头条!【环球财经】英镑兑美元汇率创10个月新高
涨见识!清明节南北习俗有何不同:北方注重修坟 南方烧纸钱等
环球微头条丨特斯拉不要的技术 蔚来当个宝?
媒体:第一批因AI失业的人已经出现!公司不会养闲人 这些职业最容易被AI取代
在四川买一个新的房子买房子需要哪些手续费
天天观察:今日清明节 专家科普都有哪些习俗:其实是三个节日融合而来
升级iOS 16.4的用户被苹果坑了!Wi-Fi/天气崩溃、电池续航大缩水
环球看热讯:95后寿衣模特回应被说阴气重 本人回应坚持做自己:任何职业都该被尊重
世界微资讯!读SQL进阶教程笔记08_处理数列
【播资讯】NVIDIA全景光追模式成硬件杀手!RTX 4090仅16帧:不开DLSS没法玩
车主集体投诉宝马id7系统虚假宣传 宝马中国回应
速看:JR:我打NBA只因为热爱篮球 从来都不是为了钱和名利
为啥天空是蓝色的?而不是彩虹一般的七彩颜色呢?
环球聚焦:一亩地几百个洞 青藏高原的鼠害泛滥成灾:但其实不怪它们
全球实时:阿里搞出脱口秀版GPT 把“鸟鸟”塞进去了?官方回应