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五大数据结构和使用场景
Apr 12 Redis
Redis安装启动及常见数据类型
Apr 14 Redis
详解Redis主从复制实践
May 19 Redis
Redis高级数据类型Hyperloglog、Bitmap的使用
May 24 Redis
浅谈Redis的几个过期策略
May 27 Redis
SpringBoot 集成Redis 过程
Jun 02 Redis
Redis性能监控的实现
Jul 09 Redis
Redis之RedisTemplate配置方式(序列和反序列化)
Mar 13 Redis
Redis基本数据类型Zset有序集合常用操作
Jun 01 Redis
Redis基本数据类型Set常用操作命令
Jun 01 Redis
Redis基本数据类型String常用操作命令
Jun 01 Redis
Redis入门基础常用操作命令整理
Jun 01 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无限分类且支持输出树状图的详细介绍
2013/06/19 PHP
php 表单提交大量数据发生丢失的解决方法
2014/03/03 PHP
php广告加载类用法实例
2014/09/23 PHP
TP(thinkPHP)框架多层控制器和多级控制器的使用示例
2018/06/13 PHP
腾讯的ip接口 方便获取当前用户的ip地理位置
2010/11/25 Javascript
在JavaScript中获取请求的URL参数
2010/12/22 Javascript
js中精确计算加法和减法示例
2014/03/28 Javascript
JS操作HTML自定义属性的方法
2015/02/10 Javascript
JavaScript的原型继承详解
2015/02/15 Javascript
JS实现横向与竖向两个选项卡Tab联动的方法
2015/09/27 Javascript
jQuery实现的自定义弹出层效果实例详解
2016/09/04 Javascript
让编辑器支持word复制黏贴、截屏的js代码
2016/10/17 Javascript
Javascrip实现文字跳动特效
2016/11/27 Javascript
利用jquery禁止外层滚动条的滚动
2017/01/05 Javascript
jQuery Validation Engine验证控件调用外部函数验证的方法
2017/01/18 Javascript
javascript中BOM基础知识总结
2017/02/14 Javascript
bootstrap手风琴折叠示例代码分享
2017/05/22 Javascript
AngularJS遍历获取数组元素的方法示例
2017/11/11 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
vue实现随机验证码功能的实例代码
2019/04/30 Javascript
图解javascript作用域链
2019/05/27 Javascript
vue 在methods中调用mounted的实现操作
2020/08/07 Javascript
浅谈鸿蒙 JavaScript GUI 技术栈
2020/09/17 Javascript
[37:35]DOTA2上海特级锦标赛A组资格赛#1 Secret VS MVP.Phx第二局
2016/02/25 DOTA
python遍历序列enumerate函数浅析
2017/10/17 Python
flask + pymysql操作Mysql数据库的实例
2017/11/13 Python
PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译
2020/04/15 Python
德国婴儿推车和儿童安全座椅商店:BABYSHOP
2016/09/01 全球购物
美国第二大连锁书店:Books-A-Million
2017/12/28 全球购物
世界上第一个创建了罩杯系统的美国内衣品牌:Maidenform
2019/03/23 全球购物
班级学习计划书
2014/04/27 职场文书
综治宣传月活动总结
2014/04/28 职场文书
2015年高考寄语或鼓励的话
2015/03/23 职场文书
检举信的写法
2019/04/10 职场文书
MySQL一些常用高级SQL语句
2021/07/03 MySQL
python 判断文件或文件夹是否存在
2022/03/18 Python