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 查看所有的key方式
May 07 Redis
Redis实现订单自动过期功能的示例代码
May 08 Redis
分布式锁为什么要选择Zookeeper而不是Redis?看完这篇你就明白了
May 21 Redis
详解Redis基本命令与使用场景
Jun 01 Redis
Redis基于Bitmap实现用户签到功能
Jun 20 Redis
解析Redis Cluster原理
Jun 21 Redis
Redis Cluster集群动态扩容的实现
Jul 15 Redis
redis数据结构之压缩列表
Mar 21 Redis
Redis实现一个账号只能登录一个设备
Apr 19 Redis
Redis特殊数据类型HyperLogLog基数统计算法讲解
Jun 01 Redis
redis protocol通信协议及使用详解
Jul 15 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
10个php函数实用却不常见
2015/10/13 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
js脚本学习 比较实用的基础
2006/09/07 Javascript
LBS blog sql注射漏洞[All version]-官方已有补丁
2007/08/26 Javascript
通过javascript设置css属性的代码
2009/12/28 Javascript
JavaScript 笔记二 Array和Date对象方法
2010/05/22 Javascript
javascript继承之为什么要继承
2012/11/10 Javascript
JS中toFixed()方法引起的问题如何解决
2012/11/20 Javascript
jquery控制表单输入框显示默认值的方法
2015/05/22 Javascript
js表单提交和submit提交的区别实例分析
2015/12/10 Javascript
Treegrid的动态加载实例代码
2016/04/29 Javascript
Javascript中return的使用与闭包详解
2017/01/11 Javascript
jquery插件ContextMenu设置右键菜单
2017/03/13 Javascript
Angular2平滑升级到Angular4的步骤详解
2017/03/29 Javascript
基于jQuery封装的分页组件
2017/06/26 jQuery
基于LayUI实现前端分页功能的方法
2017/07/22 Javascript
微信小程序自定义组件之可清除的input组件
2018/07/17 Javascript
在vue中v-bind使用三目运算符绑定class的实例
2018/09/29 Javascript
js 实现在2d平面上画8的方法
2018/10/10 Javascript
浅谈Vue SSR中的Bundle的具有使用
2019/11/21 Javascript
微信小程序实现分页加载效果
2020/11/19 Javascript
Python 包含汉字的文件读写之每行末尾加上特定字符
2016/12/12 Python
Python实现变量数值交换及判断数组是否含有某个元素的方法
2017/09/18 Python
opencv python 2D直方图的示例代码
2018/07/20 Python
Python中print和return的作用及区别解析
2019/05/05 Python
Python调用Windows API函数编写录音机和音乐播放器功能
2020/01/05 Python
Python调用OpenCV实现图像平滑代码实例
2020/06/19 Python
Scrapy项目实战之爬取某社区用户详情
2020/09/17 Python
html svg生成环形进度条的实现方法
2019/09/23 HTML / CSS
医学生自我鉴定范文
2014/03/26 职场文书
党员查摆四风问题思想汇报
2014/10/25 职场文书
综治工作汇报材料
2014/10/27 职场文书
2015年物资管理工作总结
2015/05/20 职场文书
总结一些Java常用的加密算法
2021/06/11 Java/Android
python opencv将多个图放在一个窗口的实例详解
2022/02/28 Python
第四次工业革命,打工人与机器人的竞争
2022/04/21 数码科技