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常见应用场景
Jun 23 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
Redis 彻底禁用RDB持久化操作
Jul 09 Redis
Redis RDB技术底层原理详解
Sep 04 Redis
使用redis生成唯一编号及原理示例详解
Sep 15 Redis
Redis中有序集合的内部实现方式的详细介绍
Mar 16 Redis
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
Mar 16 Redis
redis击穿 雪崩 穿透超详细解决方案梳理
Mar 17 Redis
redis数据结构之压缩列表
Mar 21 Redis
Redis数据同步之redis shake的实现方法
Apr 21 Redis
浅谈Redis缓冲区机制
Jun 05 Redis
如何使用注解方式实现 Redis 分布式锁
Jul 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下用cookie统计用户访问网页次数的代码
2010/05/09 PHP
php中单个数据库字段多列显示(单字段分页、横向输出)
2014/07/28 PHP
php+mysqli批量查询多张表数据的方法
2015/01/29 PHP
PHP制作登录异常ip检测功能的实例代码
2016/11/16 PHP
JS提交并解析后台返回的XML的代码
2008/11/03 Javascript
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
jquery animate图片模向滑动示例代码
2011/01/26 Javascript
jquery 删除cookie失效的解决方法
2013/11/12 Javascript
JS获取客户端IP地址、MAC和主机名的7个方法汇总
2014/07/21 Javascript
JavaScript操作XML文件之XML读取方法
2015/06/09 Javascript
jQuery实现非常实用漂亮的select下拉菜单选择效果
2015/11/06 Javascript
基于Jquery实现仿百度百科右侧导航代码附源码下载
2015/11/27 Javascript
基于javascript实现九九乘法表
2016/03/27 Javascript
Es6 写的文件import 起来解决方案详解
2016/12/13 Javascript
JS 实现 ajax 异步浏览器兼容问题
2017/01/21 Javascript
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
微信小程序实现自定义加载图标功能
2018/07/19 Javascript
Angularjs实现数组随机排序的方法
2018/10/02 Javascript
JS实现图片切换效果
2018/11/17 Javascript
JavaScript计算正方形面积
2019/11/26 Javascript
Vue.js实现大屏数字滚动翻转效果
2019/11/29 Javascript
微信小程序中插入激励视频广告并获取收益(实例代码)
2019/12/06 Javascript
jquery html添加元素/删除元素操作实例详解
2020/05/20 jQuery
[01:05:32]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#1COL VS Alliance第一局
2016/03/04 DOTA
python实现查询苹果手机维修进度
2015/03/16 Python
Python使用matplotlib的pie函数绘制饼状图功能示例
2018/01/08 Python
python 实现汉诺塔游戏
2020/11/28 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
Liu Jo西班牙官网:意大利服装品牌
2019/09/11 全球购物
后勤人员自我评价怎么写
2013/09/19 职场文书
网站编辑求职信
2013/10/17 职场文书
税务干部鉴定材料
2014/02/11 职场文书
高中国旗下的演讲稿
2014/08/28 职场文书
关于调整工作时间的通知
2015/04/24 职场文书
html+css实现文字折叠特效实例
2021/06/02 HTML / CSS
WIN10使用IIS部署ftp服务器详细教程
2022/08/05 Servers