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";
    }

}
相关推荐
新缸中之脑1 分钟前
用Claude for Word审查法律合同
开发语言·c#·word
沐知全栈开发3 分钟前
SQLite 子查询
开发语言
indexsunny6 分钟前
互联网大厂Java求职面试实战:Spring Boot微服务在电商场景中的应用与挑战
java·spring boot·redis·面试·kafka·oauth2·microservices
Codigger官方8 分钟前
生态破局:从孤岛工具到协同奇点
开发语言·人工智能·程序人生
RATi GORI9 分钟前
SQL中的DISTINCT、SQL DISTINCT详解、DISTINCT的用法、DISTINCT注意事项
java·数据库·sql
莫逸风10 分钟前
【java-core-collections】B+ 树深度解析
android·java·开发语言
gihigo199811 分钟前
MATLAB中实现混沌序列的相空间重构
开发语言·matlab·重构
xzl0412 分钟前
RT-Thread 5.2.2内核模块
开发语言·rt-thread
Wenzar_12 分钟前
**发散创新:基于算子融合的深度学习推理优化实战**在现代AI推理场景中,模型性能瓶颈往往不是由单一算子决定的,而是多个连续算子之间数
java·人工智能·深度学习
我命由我1234513 分钟前
Android 开发问题:无法从存储库 “D:\keys\MyNotifications.jks“ 中读取密钥 MyNotifications.
android·java·java-ee·android studio·android jetpack·android-studio·android runtime