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通过6379端口无法连接服务器(redis-server.exe闪退)
May 08 Redis
详解Redis主从复制实践
May 19 Redis
redis哨兵常用命令和监控示例详解
May 27 Redis
k8s部署redis cluster集群的实现
Jun 24 Redis
Redis做数据持久化的解决方案及底层原理
Jul 15 Redis
springboot使用Redis作缓存使用入门教程
Jul 25 Redis
Redis读写分离搭建的完整步骤
Sep 14 Redis
Redis安装使用RedisJSON模块的方法
Mar 23 Redis
redis sentinel监控高可用集群实现的配置步骤
Apr 01 Redis
浅谈Redis缓冲区机制
Jun 05 Redis
Redis主从复制操作和配置详情
Sep 23 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 常用函数库和一些实用小技巧
2009/01/01 PHP
php split汉字
2009/06/05 PHP
php上传图片之时间戳命名(保存路径)
2014/08/15 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
2017/09/16 PHP
createElement动态创建HTML对象脚本代码
2008/11/24 Javascript
javascript 写的一个简单的timer
2009/07/30 Javascript
jQuery中复合属性选择器用法实例
2014/12/31 Javascript
jquery专业的导航菜单特效代码分享
2015/08/29 Javascript
基于jQuery实现的无刷新表格分页实例
2016/02/17 Javascript
jQuery grep()方法详解及实例代码
2016/10/30 Javascript
使用vue框架 Ajax获取数据列表并用BootStrap显示出来
2017/04/24 Javascript
vue页面使用阿里oss上传功能的实例(一)
2017/08/09 Javascript
使用JavaScript实现一个小程序之99乘法表
2017/09/21 Javascript
[48:30]LGD vs infamous Supermajor小组赛D组 BO3 第一场 6.3
2018/06/04 DOTA
在Python中的Django框架中进行字符串翻译
2015/07/27 Python
python调用系统ffmpeg实现视频截图、http发送
2018/03/06 Python
pandas数值计算与排序方法
2018/04/12 Python
python读取文件名称生成list的方法
2018/04/27 Python
详解python中Numpy的属性与创建矩阵
2018/09/10 Python
python实现图片压缩代码实例
2019/08/12 Python
Python Numpy中数据的常用保存与读取方法
2020/04/01 Python
python 中关于pycharm选择运行环境的问题
2020/10/31 Python
python爬虫分布式获取数据的实例方法
2020/11/26 Python
HTML5中canvas中的beginPath()和closePath()的重要性
2018/08/24 HTML / CSS
使用placeholder属性设置input文本框的提示信息
2020/02/19 HTML / CSS
照片礼物和装饰:MyPhoto
2019/11/02 全球购物
面向对象设计的原则是什么
2013/02/13 面试题
重写子类方法时,抛出异常的书写注意事项
2015/10/17 面试题
周鸿祎:教你写创业计划书
2013/12/30 职场文书
现场活动策划方案
2014/08/22 职场文书
党员自评材料范文
2014/12/17 职场文书
大学生自我推荐信范文
2015/03/24 职场文书
2015年度个人工作总结报告
2015/10/24 职场文书
关于践行三严三实的心得体会
2016/01/05 职场文书
PyQt5结合QtDesigner实现文本框读写操作
2021/06/11 Python
Python利用zhdate模块实现农历日期处理
2022/03/31 Python