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
基于Redis位图实现用户签到功能
May 08 Redis
基于Redis延迟队列的实现代码
May 13 Redis
你真的了解redis为什么要提供pipeline功能
Jun 22 Redis
浅谈Redis中的RDB快照
Jun 29 Redis
Redis做数据持久化的解决方案及底层原理
Jul 15 Redis
为什么RedisCluster设计成16384个槽
Sep 25 Redis
Redis命令处理过程源码解析
Feb 12 Redis
在Centos 8.0中安装Redis服务器的教程详解
Mar 21 Redis
Redis实战高并发之扣减库存项目
Apr 14 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中return 和 exit 、break和contiue 区别与用法
2012/04/09 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
PHP添加图片水印、压缩、剪切的封装类
2015/08/17 PHP
PHP 将数组打乱 shuffle函数的用法及简单实例
2016/06/17 PHP
php 比较获取两个数组相同和不同元素的例子(交集和差集)
2019/10/18 PHP
Js 获取HTML DOM节点元素的方法小结
2009/04/24 Javascript
javascript将数组插入到另一个数组中的代码
2013/01/10 Javascript
简洁Ajax函数处理(示例代码)
2013/11/15 Javascript
网站繁简切换的JS遇到页面卡死的解决方法
2014/03/12 Javascript
JQUERY简单按钮轮换选中效果实现方法
2015/05/07 Javascript
javascript获取重复次数最多的字符
2015/07/08 Javascript
zTree实现节点修改的实时刷新功能
2017/03/20 Javascript
node.js中TCP Socket多进程间的消息推送示例详解
2018/07/10 Javascript
使用pkg打包Node.js应用的方法步骤
2018/10/19 Javascript
性能优化篇之Webpack构建速度优化的建议
2019/04/03 Javascript
回顾Javascript React基础
2019/06/15 Javascript
javascript事件循环event loop的简单模型解释与应用分析
2020/03/14 Javascript
[42:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS OpTic
2018/03/31 DOTA
用Python脚本生成Android SALT扰码的方法
2013/09/18 Python
小议Python中自定义函数的可变参数的使用及注意点
2016/06/21 Python
Python抓取框架Scrapy爬虫入门:页面提取
2017/12/01 Python
flask中的wtforms使用方法
2018/07/21 Python
在Pandas中给多层索引降级的方法
2018/11/16 Python
pyqt实现.ui文件批量转换为对应.py文件脚本
2019/06/19 Python
在pycharm下设置自己的个性模版方法
2019/07/15 Python
jupyter notebook 增加kernel教程
2020/04/10 Python
Pycharm中如何关掉python console
2020/10/27 Python
eBay美国官网:eBay.com
2020/10/24 全球购物
中专生毕业自我鉴定
2013/11/01 职场文书
节约用水的口号
2014/06/20 职场文书
户籍证明书标准模板
2014/09/10 职场文书
学习十八大的心得体会
2014/09/12 职场文书
交警正风肃纪剖析材料
2014/10/29 职场文书
详解Redis基本命令与使用场景
2021/06/01 Redis
新手入门Mysql--概念
2021/06/18 MySQL
vscode远程免密登入Linux服务器的配置方法
2022/06/28 Servers