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实现分布式锁的方法(lua脚本版)
May 12 Redis
redis内存空间效率问题的深入探究
May 17 Redis
详解Redis复制原理
Jun 04 Redis
缓存替换策略及应用(以Redis、InnoDB为例)
Jul 25 Redis
解析redis hash应用场景和常用命令
Aug 04 Redis
Redis入门教程详解
Aug 30 Redis
Redis的字符串是如何实现的
Oct 24 Redis
基于Redis zSet实现滑动窗口对短信进行防刷限流的问题
Feb 12 Redis
面试分析分布式架构Redis热点key大Value解决方案
Mar 13 Redis
浅谈Redis 中的过期删除策略和内存淘汰机制
Apr 03 Redis
windows安装 redis 6.2.6最新步骤详解
Apr 26 Redis
利用Redis实现点赞功能的示例代码
Jun 28 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
yii2.0整合阿里云oss删除单个文件的方法
2017/09/19 PHP
PHP Trait代码复用类与多继承实现方法详解
2019/06/17 PHP
用js怎么把&amp;字符换成&quot;&amp;amp:&quot;
2006/10/19 Javascript
JavaScript之HTMLCollection接口代码
2011/04/27 Javascript
Javascript base64编码实现代码
2011/12/02 Javascript
Javascript学习笔记之函数篇(五) : 构造函数
2014/11/23 Javascript
JavaScript获得表单target属性的方法
2015/04/02 Javascript
详解JavaScript中循环控制语句的用法
2015/06/03 Javascript
JavaScript使用RegExp进行正则匹配的方法
2015/07/11 Javascript
基于jQuery实现Div窗口震动特效代码-代码简单
2015/08/28 Javascript
jQuery基于ajax()使用serialize()提交form数据的方法
2015/12/08 Javascript
JavaScript实现图片滑动切换的代码示例分享
2016/03/06 Javascript
js中string和number类型互转换技巧(分享)
2016/11/28 Javascript
bootstrap手风琴制作方法详解
2017/01/11 Javascript
一次围绕setTimeout的前端面试经验分享
2017/06/15 Javascript
node.js自动上传ftp的脚本分享
2018/06/16 Javascript
vue超时计算的组件实例代码
2018/07/09 Javascript
Vue.js构建你的第一个包并在NPM上发布的方法步骤
2019/05/01 Javascript
浅谈React Native 传参的几种方式(小结)
2019/05/21 Javascript
[11:12]2018DOTA2国际邀请赛寻真——绿色长城OpTic
2018/08/10 DOTA
python的Template使用指南
2014/09/11 Python
Python实现学校管理系统
2018/01/11 Python
对Xpath 获取子标签下所有文本的方法详解
2019/01/02 Python
Python txt文件加入字典并查询的方法
2019/01/15 Python
python opencv实现图像边缘检测
2019/04/29 Python
浅析Python打包时包含静态文件处理方法
2021/01/15 Python
如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
2016/12/22 HTML / CSS
HTML5中input输入框默认提示文字向左向右移动的示例代码
2020/09/10 HTML / CSS
美国流行背包品牌:JanSport(杰斯伯)
2018/03/02 全球购物
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
医学护理毕业生自荐信
2013/11/07 职场文书
校园十佳歌手策划书
2014/01/22 职场文书
特色冷饮店创业计划书
2014/01/28 职场文书
人大调研汇报材料
2014/08/14 职场文书
中学生逃课检讨书
2015/02/17 职场文书
答谢酒会主持词
2015/07/02 职场文书