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遍历所有key的两个命令(KEYS 和 SCAN)
Apr 12 Redis
Redis数据结构之链表与字典的使用
May 11 Redis
redis实现的四种常见限流策略
Jun 18 Redis
redis使用不当导致应用卡死bug的过程解析
Jul 01 Redis
Redis 常见使用场景
Aug 30 Redis
SpringBoot集成Redis的思路详解
Oct 16 Redis
Redis Stream类型的使用详解
Nov 11 Redis
redis数据一致性的实现示例
Mar 18 Redis
基于Redis6.2.6版本部署Redis Cluster集群的问题
Apr 01 Redis
Redis实现一个账号只能登录一个设备
Apr 19 Redis
详解Redis的三种常用的缓存读写策略步骤
May 06 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之第七天
2006/10/09 PHP
PHP将XML转数组过程详解
2013/11/13 PHP
在Mac上编译安装PHP7的开发环境
2015/07/28 PHP
两种php实现图片上传的方法
2016/01/22 PHP
javascript实现百度地图鼠标滑动事件显示、隐藏
2015/04/02 Javascript
基于javascript实现图片预加载
2016/01/05 Javascript
js获取当前年月日-YYYYmmDD格式的实现代码
2016/06/01 Javascript
ionic由于使用了header和subheader导致被遮挡的问题的两种解决方法
2016/09/22 Javascript
jQuery使用方法
2017/02/04 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
Cpage.js给组件绑定事件的实现代码
2017/08/31 Javascript
JS实现点击循环切换显示内容的方法
2017/10/19 Javascript
jQuery轮播图实例详解
2018/08/15 jQuery
vue项目中实现图片预览的公用组件功能
2018/10/26 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
2019/09/25 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
2019/10/28 Javascript
jQuery+Ajax+js实现请求json格式数据并渲染到html页面操作示例
2020/06/02 jQuery
JS PHP字符串截取函数实现原理解析
2020/08/29 Javascript
vue任意关系组件通信与跨组件监听状态vue-communication
2020/10/18 Javascript
python如何通过实例方法名字调用方法
2018/03/21 Python
在Python中将函数作为另一个函数的参数传入并调用的方法
2019/01/22 Python
利用Python模拟登录pastebin.com的实现方法
2019/07/12 Python
python实现图片二值化及灰度处理方式
2019/12/07 Python
如何在windows下安装Pycham2020软件(方法步骤详解)
2020/05/03 Python
Speedo澳大利亚官网:全球领先游泳品牌
2018/02/04 全球购物
瑞士灯具购物网站:Lampenwelt.ch
2018/07/08 全球购物
什么是事务?事务有哪些性质?
2012/03/11 面试题
工程力学专业毕业生求职信
2013/10/06 职场文书
大学军训通讯稿
2014/01/13 职场文书
《中华少年》教学反思
2014/02/15 职场文书
《小蝌蚪找妈妈》教学反思
2014/02/21 职场文书
财务内勤岗位职责
2014/04/17 职场文书
文秘个人求职信范文
2014/04/22 职场文书
师范生免费教育协议书范本
2014/10/09 职场文书
因个人工作失误检讨书
2019/06/21 职场文书
2019暑期安全倡议书!
2019/06/27 职场文书