redis能够采用什么样的方式来实现限流
这篇文章主要介绍redis能够采用什么样的方式来实现限流,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
目的:
实现访问频率限制
实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次
非脚本实现
privatebooleanaccessLimit(Stringip,intlimit,inttime,Jedisjedis){booleanresult=true;Stringkey="rate.limit:"+ip;if(jedis.exists(key)){longafterValue=jedis.incr(key);if(afterValue>limit){result=false;}}else{Transactiontransaction=jedis.multi();transaction.incr(key);transaction.expire(key,time);transaction.exec();}returnresult;}
以上代码有两点缺陷
可能会出现竞态条件: 解决方法是用 WATCH 监控 rate.limit:$IP 的变动, 但较为麻烦;以上代码在不使用 pipeline 的情况下最多需要向Redis请求5条指令, 传输过多.
Lua脚本实现
Redis 允许将 Lua 脚本传到 Redis 服务器中执行, 脚本内可以调用大部分 Redis 命令, 且 Redis 保证脚本的原子性:
首先需要准备Lua代码: script.lua
----CreatedbyIntelliJIDEA.--User:jifang--Date:16/8/24--Time:下午6:11--localkey="rate.limit:"..KEYS[1]locallimit=tonumber(ARGV[1])localexpire_time=ARGV[2]localis_exists=redis.call("EXISTS",key)ifis_exists==1thenifredis.call("INCR",key)>limitthenreturn0elsereturn1endelseredis.call("SET",key,1)redis.call("EXPIRE",key,expire_time)return1end
Java
privatebooleanaccessLimit(Stringip,intlimit,inttimeout,Jedisconnection)throwsIOException{List<String>keys=Collections.singletonList(ip);List<String>argv=Arrays.asList(String.valueOf(limit),String.valueOf(timeout));return1==(long)connection.eval(loadScriptString("script.lua"),keys,argv);}//加载Lua代码privateStringloadScriptString(StringfileName)throwsIOException{Readerreader=newInputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName));returnCharStreams.toString(reader);}
Lua 嵌入 Redis 优势:
减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用。
以上是“redis能够采用什么样的方式来实现限流”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。