Lua脚本实现滑动窗口

Lua脚本实现滑动窗口

一级目录

java 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

public class ApplicationTempTest {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private String KEY_PREFIX  = "ni:ai:flow:limit:";
    private long WINDOW_MILLISECOND = 60 * 1000L;
    DefaultRedisScript<Long> script = new DefaultRedisScript<>();

    @PostConstruct
    public void scriptInit() {
        script.setScriptText(getFlowLimitLuaScript());
        script.setResultType(Long.class);
    }
        
    @Test
    public void testA() {
        String userId = "NEW_YY_1566";
        // 用户隔离级别
        // 设计一个滑动窗口算法。一分钟内,task1可以调用5次,task2可以调用10次
        Map<String, Integer> taskMap = new HashMap<>();
        taskMap.put("task1", 5);
        taskMap.put("task2", 10);

        taskMap.forEach((taskId, val) -> {
            boolean allow = allowRequest(taskId, val, WINDOW_MILLISECOND, userId);
            if (allow) {
                System.out.println(taskId + "可以继续执行!");
            } else {
                System.out.println(taskId + "不能继续执行!");
            }
        });
    }

    public boolean allowRequest(String key, long limit, Long windowMillisecond, String userId) {
        List<String> keys = Collections.singletonList(KEY_PREFIX + key);
        List<String> args = Arrays.asList(String.valueOf(limit), String.valueOf(windowMillisecond), String.valueOf(System.currentTimeMillis()), userId);
        Long result = stringRedisTemplate.execute(script, keys, args.toArray());
        // 判断脚本返回结果。限流0,允许1
        return result != null && result == 1;
    }

    public String getFlowLimitLuaScript() {
        return "local key = KEYS[1]\n" +
                "local maxRequests = tonumber(ARGC[1])\n" +
                "local windowMs = tonumber(ARGC[2])\n" +
                "local now = tonumber(ARGC[3])\n" +
                "local user_id = ARGC[4]\n" +
//                "-- 删除过期的记录(时间戳 < now - windows)\n" +
                "redis.call('ZREMRANGEBYSCORE', key, 0, now-windowMs)\n" +
//                "-- 获取当前窗口内的请求数\n" +
                "local count = redis.call('ZCARD', key)\n" +
//                "-- 判断是否超过限制(限流返回0,允许返回1)\n" +
                "if count >= maxRequests then\n" +
                "   return 0\n" +
                "else\n" +
//                "-- 添加当前请求\n" +
                "   redis.call('ZADD', key, now, user_id .. ':' .. now)\n" +
                "   return 1\n" +
                "end";
    }

}
相关推荐
zhangjw3413 小时前
第9篇:Java集合框架入门,List详解:ArrayList与LinkedList底层彻底吃透
java·开发语言·list
大大杰哥13 小时前
Java集合框架(List/Set/Queue)核心总结与代码示例
java·数据结构
报错小能手13 小时前
Swift经典面试题汇总
开发语言·ios·swift
深蓝轨迹13 小时前
RedisTemplate 核心操作API汇总(Spring Data Redis)
java·redis·spring
得一录13 小时前
TradingAgents金融股票分析的最小实现
开发语言·数据库·人工智能·python
yuanpan13 小时前
Python 与 Conda 编程实战指南:从环境配置到项目运行完整入门
开发语言·python·conda
Cat_Rocky13 小时前
K8s RBAC认证 简单讲
java·docker·kubernetes
一只IT攻城狮13 小时前
️ Spring Boot 文件上传,防御恶意文件攻击
java·spring boot·web安全
水木流年追梦13 小时前
大模型入门-应用篇1-prompt技术
开发语言·python·算法·prompt
莫生灬灬13 小时前
ElementUI封装 共91个组件 支持易语言/火山/C#/Python
开发语言·c++·python·ui·elementui·c#