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高级数据类型Hyperloglog、Bitmap的使用
May 24 Redis
redis requires ruby version2.2.2的解决方案
Jul 15 Redis
浅谈Redis位图(Bitmap)及Redis二进制中的问题
Jul 15 Redis
为什么RedisCluster设计成16384个槽
Sep 25 Redis
Redis高并发防止秒杀超卖实战源码解决方案
Nov 01 Redis
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
Mar 16 Redis
一文搞懂Redis中String数据类型
Apr 03 Redis
redis 解决库存并发问题实现数量控制
Apr 08 Redis
Redis中key的过期删除策略和内存淘汰机制
Apr 12 Redis
Redis特殊数据类型bitmap位图
Jun 01 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 strncasecmp字符串比较的小技巧
2011/01/04 PHP
php在linux下检测mysql同步状态的方法
2015/01/15 PHP
详解WordPress中添加友情链接的方法
2016/05/21 PHP
PHP中include和require的区别实例分析
2017/05/07 PHP
jquery动态添加删除div 具体实现
2013/07/20 Javascript
jquery mobile的触控点击事件会多次触发问题的解决方法
2014/05/08 Javascript
JavaScript动态提示输入框输入字数的方法
2015/07/27 Javascript
AngularJS 使用 UI Router 实现表单向导
2016/01/29 Javascript
深入理解JS中的substr和substring
2016/04/26 Javascript
js实现分页功能
2017/05/24 Javascript
Three.js利用Detector.js插件如何实现兼容性检测详解
2017/09/26 Javascript
JavaScript实现多态和继承的封装操作示例
2018/08/20 Javascript
微信小程序实现获取用户信息并存入数据库操作示例
2019/05/07 Javascript
layui自己添加图片按钮并点击跳转页面的例子
2019/09/14 Javascript
Jquery高级应用Deferred对象原理及使用实例
2020/05/28 jQuery
jquery实现鼠标悬浮弹出气泡提示框
2020/12/23 jQuery
python3抓取中文网页的方法
2015/07/28 Python
Python中动态创建类实例的方法
2017/03/24 Python
Python使用pylab库实现画线功能的方法详解
2017/06/08 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
python实现任意位置文件分割的实例
2018/12/14 Python
Pycharm2020.1安装无法启动问题即设置中文插件的方法
2020/08/07 Python
15款Python编辑器的优缺点,别再问我“选什么编辑器”啦
2020/10/19 Python
css3模拟jq点击事件的实例代码
2017/07/06 HTML / CSS
加拿大领先的牛仔零售商:Bluenotes
2018/01/22 全球购物
请解释接口的显式实现有什么意义
2012/05/26 面试题
顺丰快递Java软件工程师面试题
2015/07/31 面试题
毕业生物理教师求职信
2013/10/17 职场文书
上班早退检讨书
2014/01/09 职场文书
先进党支部事迹材料
2014/01/13 职场文书
水果连锁超市创业计划书
2014/01/24 职场文书
总经理工作职责范文
2014/03/14 职场文书
委托书格式
2014/08/01 职场文书
高中校园广播稿3篇
2014/09/29 职场文书
水电工岗位职责
2015/02/14 职场文书
严以修身专题学习研讨会发言材料
2015/11/09 职场文书