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 24 Redis
Redis持久化与主从复制的实践
Apr 27 Redis
浅谈redis缓存在项目中的使用
May 20 Redis
Redis模仿手机验证码发送的实现示例
Nov 02 Redis
Spring Boot实战解决高并发数据入库之 Redis 缓存+MySQL 批量入库问题
Feb 12 Redis
Redis监控工具RedisInsight安装与使用
Mar 21 Redis
源码分析Redis中 set 和 sorted set 的使用方法
Mar 22 Redis
Redis安装使用RedisJSON模块的方法
Mar 23 Redis
浅谈Redis 中的过期删除策略和内存淘汰机制
Apr 03 Redis
redis复制有可能碰到的问题汇总
Apr 03 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中获取内网用户MAC地址(WINDOWS/linux)的实现代码
2011/08/11 PHP
smarty中js的调用方法示例
2014/10/27 PHP
php图像处理函数imagecopyresampled用法详解
2016/12/02 PHP
extJs 常用到的增,删,改,查操作代码
2009/12/28 Javascript
该如何加载google-analytics(或其他第三方)的JS
2010/05/13 Javascript
Node.js实战 建立简单的Web服务器
2012/03/08 Javascript
javascript 获取模态窗口的滚动位置代码
2013/08/06 Javascript
多种方法判断Javascript对象是否存在
2013/09/22 Javascript
appendChild() 或 insertBefore()使用与区别介绍
2013/10/11 Javascript
js查找节点的方法小结
2015/01/13 Javascript
在Node.js应用中使用Redis的方法简介
2015/06/24 Javascript
js实现浮动在网页右侧的简洁QQ在线客服代码
2015/09/04 Javascript
JS与Ajax Get和Post在使用上的区别实例详解
2016/06/08 Javascript
js验证手机号、密码、短信验证码代码工具类
2020/06/24 Javascript
js实现华丽的九九乘法表效果
2017/03/29 Javascript
基于javascript的异步编程实例详解
2017/04/10 Javascript
webpack 打包压缩js和css的方法示例
2018/03/20 Javascript
[05:43]VG.R战队教练Mikasa专访:为目标从未停止战斗
2016/08/02 DOTA
Python入门_条件控制(详解)
2017/05/16 Python
Python实现压缩和解压缩ZIP文件的方法分析
2017/09/28 Python
Python中int()函数的用法浅析
2017/10/17 Python
pandas值替换方法
2018/07/10 Python
对Python3.x版本print函数左右对齐详解
2018/12/22 Python
Python assert语句的简单使用示例
2019/07/28 Python
图解python全局变量与局部变量相关知识
2019/11/02 Python
关于Pytorch MaxUnpool2d中size操作方式
2020/01/03 Python
详解CSS3浏览器兼容
2016/12/14 HTML / CSS
纽约手袋品牌:KARA
2018/03/18 全球购物
经典c++面试题二
2015/08/14 面试题
大型活动策划方案
2014/01/12 职场文书
产品发布会策划方案
2014/05/12 职场文书
学习十八大的心得体会
2014/09/01 职场文书
2014年社区工会工作总结
2014/12/18 职场文书
升职自我推荐信范文
2015/03/25 职场文书
2016年党校科级干部培训班学习心得体会
2016/01/06 职场文书
简单聊聊TypeScript只读修饰符
2022/04/06 Javascript