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基于Bitmap实现用户签到功能
Jun 20 Redis
Redis Cluster集群动态扩容的实现
Jul 15 Redis
浅谈Redis位图(Bitmap)及Redis二进制中的问题
Jul 15 Redis
Redis集群新增、删除节点以及动态增加内存的方法
Sep 04 Redis
基于Redis结合SpringBoot的秒杀案例详解
Oct 05 Redis
Redis的字符串是如何实现的
Oct 24 Redis
linux下安装redis图文详细步骤
Dec 04 Redis
Redis+Lua脚本实现计数器接口防刷功能(升级版)
Feb 12 Redis
Redis分布式锁的7种实现
Apr 01 Redis
 Redis 串行生成顺序编码的方法实现
Apr 03 Redis
Redis如何实现验证码发送 以及限制每日发送次数
Apr 18 Redis
Redis基本数据类型Set常用操作命令
Jun 01 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
DIY一个适配电脑声卡的动圈话筒放大器
2021/03/02 无线电
PHP实现模仿socket请求返回页面的方法
2014/11/04 PHP
thinkPHP框架中layer.js的封装与使用方法示例
2019/01/18 PHP
PHP whois查询类定义与用法示例
2019/04/03 PHP
[原创]网络复制内容时常用的正则+editplus
2006/11/30 Javascript
js计算页面刷新的次数
2009/07/20 Javascript
分享20多个很棒的jQuery 文件上传插件或教程
2011/09/04 Javascript
JavaScript实现的石头剪刀布游戏源码分享
2014/08/22 Javascript
jQuery中extend函数的实现原理详解
2015/02/03 Javascript
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
2015/03/14 Javascript
jQuery EasyUI学习教程之datagrid点击列表头排序
2016/07/09 Javascript
ES6新特性之模块Module用法详解
2017/04/01 Javascript
JQuery扩展对象方法操作示例
2018/08/21 jQuery
基于 vue-skeleton-webpack-plugin 的骨架屏实战
2019/08/05 Javascript
node.js实现http服务器与浏览器之间的内容缓存操作示例
2020/02/11 Javascript
Vue 技巧之控制父类的 slot
2020/02/24 Javascript
深入理解Python中字典的键的使用
2015/08/19 Python
python解决网站的反爬虫策略总结
2016/10/26 Python
python复制文件到指定目录的实例
2018/04/27 Python
python递归法解决棋盘分割问题
2019/07/17 Python
Python实现电视里的5毛特效实例代码详解
2020/05/15 Python
Python脚本破解压缩文件口令实例教程(zipfile)
2020/06/14 Python
Kickers鞋英国官网:男士、女士和儿童鞋
2021/03/08 全球购物
Solaris操作系统的线程机制
2015/07/28 面试题
初中生自我评价
2014/02/01 职场文书
自我评价的范文
2014/02/02 职场文书
幼儿园大班毕业教师寄语
2014/04/03 职场文书
幼儿园中班评语大全
2014/04/17 职场文书
投标承诺书怎么写
2014/05/24 职场文书
英语教育专业毕业生求职信
2014/08/28 职场文书
自愿离婚协议书2015
2015/01/26 职场文书
客房部经理岗位职责
2015/02/02 职场文书
行政二审代理词
2015/05/25 职场文书
党小组推荐意见
2015/06/02 职场文书
2016大学迎新欢迎词
2015/09/29 职场文书
HTML5中的DOCUMENT.VISIBILITYSTATE属性详解
2023/05/07 HTML / CSS