Redis Lua脚本实现ip限流示例


Posted in Redis onJuly 15, 2022

引言

分布式限流最关键的是要将限流服务做成原子化,而解决方案可以使使用redis+lua或者nginx+lua技术进行实现,通过这两种技术可以实现的高并发和高性能。
首先我们来使用redis+lua实现时间窗内某个接口的请求数限流,实现了该功能后可以改造为限流总并发/请求数和限制总资源数。Lua本身就是一种编程语言,也可以使用它实现复杂的令牌桶或漏桶算法。
如下操作因是在一个lua脚本中(相当于原子操作),又因Redis是单线程模型,因此是线程安全的。

相比Redis事务来说,Lua脚本有以下优点

减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;
原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用.

Lua脚本

local key = KEYS[1] --限流KEY(一秒一个)
local limit = tonumber(ARGV[1]) --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小
    return 0
else --请求数+1,并设置2秒过期
    redis.call("INCRBY", key,"1")
    redis.call("expire", key,"2")
end
return 1

java代码

import org.apache.commons.io.FileUtils;
import redis.clients.jedis.Jedis;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class RedisLimitRateWithLUA {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(1);
        for (int i = 0; i < 7; i++) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        latch.await();
                        System.out.println("请求是否被执行:"+accquire());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        latch.countDown();
    }
    public static boolean accquire() throws IOException, URISyntaxException {
        Jedis jedis = new Jedis("127.0.0.1");
        File luaFile = new File(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath() + "limit.lua");
        String luaScript = FileUtils.readFileToString(luaFile);
        String key = "ip:" + System.currentTimeMillis()/1000; // 当前秒
        String limit = "5"; // 最大限制
        List<String> keys = new ArrayList<String>();
        keys.add(key);
        List<String> args = new ArrayList<String>();
        args.add(limit);
        Long result = (Long)(jedis.eval(luaScript, keys, args)); // 执行lua脚本,传入参数
        return result == 1;
    }
}

运行结果

请求是否被执行:true
请求是否被执行:true
请求是否被执行:false
请求是否被执行:true
请求是否被执行:true
请求是否被执行:true
请求是否被执行:fals

从结果可看出只有5个请求成功执行

IP限流Lua脚本

local key = "rate.limit:" .. KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2]
local is_exists = redis.call("EXISTS", key)
if is_exists == 1 then
    if redis.call("INCR", key) > limit then
        return 0
    else
        return 1
    end
else
    redis.call("SET", key, 1)
    redis.call("EXPIRE", key, expire_time)
    return 1
end

以上就是Redis Lua脚本实现ip限流示例的详细内容,更多关于Redis Lua限流的资料请关注三水点靠木其它相关文章!


Tags in this post...

Redis 相关文章推荐
redis 限制内存使用大小的实现
May 08 Redis
redis三种高可用方式部署的实现
May 11 Redis
压缩Redis里的字符串大对象操作
Jun 23 Redis
Redis集群的关闭与重启操作
Jul 07 Redis
浅谈Redis的keys命令到底有多慢
Oct 05 Redis
CentOS8.4安装Redis6.2.6的详细过程
Nov 20 Redis
面试分析分布式架构Redis热点key大Value解决方案
Mar 13 Redis
源码分析Redis中 set 和 sorted set 的使用方法
Mar 22 Redis
sentinel支持的redis高可用集群配置详解
Apr 01 Redis
Redis 限流器
May 15 Redis
Redis基本数据类型Zset有序集合常用操作
Jun 01 Redis
浅谈Redis缓冲区机制
Jun 05 Redis
redis protocol通信协议及使用详解
Jul 15 #Redis
Redis sentinel哨兵集群的实现步骤
Jul 15 #Redis
Redis唯一ID生成器的实现
Jul 07 #Redis
Redis+AOP+自定义注解实现限流
Jun 28 #Redis
利用Redis实现点赞功能的示例代码
Jun 28 #Redis
一文教你快速生成MySQL数据库关系图
Jun 28 #Redis
Redis实现主从复制方式(Master&Slave)
Jun 21 #Redis
You might like
php自定义排序uasort函数示例【二维数组按指定键值排序】
2019/06/19 PHP
top.location.href 没有权限 解决方法
2008/08/05 Javascript
Discuz! 6.1_jQuery兼容问题
2008/09/23 Javascript
js处理表格对table进行修饰
2014/05/26 Javascript
AngularJS入门教程之迭代器过滤详解
2016/08/18 Javascript
AngularJS constant和value区别详解
2017/02/28 Javascript
weebox弹出窗口不居中显示的解决方法
2017/11/27 Javascript
vue项目首屏加载时间优化实战
2019/04/23 Javascript
jquery 回调操作实例分析【回调成功与回调失败的情况】
2019/09/27 jQuery
vue 路由子组件created和mounted不起作用的解决方法
2019/11/05 Javascript
JQuery获得内容和属性方法解析
2020/05/30 jQuery
微信小程序之导航滑块视图容器功能的实现代码(简单两步)
2020/06/19 Javascript
[14:19]2018年度COSER大赛-完美盛典
2018/12/16 DOTA
Python中文编码那些事
2014/06/25 Python
python中的__slots__使用示例
2015/02/26 Python
python遍历类中所有成员的方法
2015/03/18 Python
Python实现模拟登录及表单提交的方法
2015/07/25 Python
Python正则表达式使用范例分享
2016/12/04 Python
利用python实现简单的循环购物车功能示例代码
2017/07/05 Python
python 调用有道api接口的方法
2019/01/03 Python
Python机器学习算法库scikit-learn学习之决策树实现方法详解
2019/07/04 Python
python实现遍历文件夹图片并重命名
2020/03/23 Python
html5 CSS过度-webkit-transition使用介绍
2013/07/02 HTML / CSS
美国时尚女装在线:Missguided
2016/12/03 全球购物
6PM官网:折扣鞋、服装及配饰
2018/08/03 全球购物
小学班主任评语大全
2014/04/23 职场文书
经济管理专业求职信
2014/06/09 职场文书
教师自我剖析材料(四风问题)
2014/09/30 职场文书
政风行风建设整改方案
2014/10/27 职场文书
教师党员自我评价范文
2015/03/04 职场文书
文明礼仪倡议书
2015/04/28 职场文书
房地产置业顾问工作总结
2015/10/23 职场文书
教您怎么制定西餐厅运营方案 ?
2019/07/05 职场文书
经典哲理警句:志不真则心不热,心不热则功不贤
2019/11/14 职场文书
python Tkinter的简单入门教程
2021/04/11 Python
美国运营商 T-Mobile 以 117.83Mb/s 的速度排第一位
2022/04/21 数码科技