当前位置: 首页 > news >正文

redis+lua+固定窗口实现分布式限流

用key的过期时间替代固定窗口的时间戳

-- KEYS[1]: 限流的key
-- ARGV[1]: 限流窗口大小(秒)
-- ARGV[2]: 限流阈值local key = KEYS[1]
local window = tonumber(ARGV[1])
local limit = tonumber(ARGV[2])-- 尝试获取当前计数
local current = redis.call("GET", key)if current == false then-- key不存在,初始化计数器并设置过期时间redis.call("SET", key, 1, "EX", window)return 1
else-- key存在,检查是否超过限制if tonumber(current) < limit thenredis.call("INCR", key)return 1elsereturn 0end
end

java客户端

public class FixedWindowRateLimiterWithTTL {private Jedis jedis;private String key;private int window; // 窗口大小(秒)private int limit;  // 限流阈值private static final String LUA_SCRIPT ="local key = KEYS[1]\n" +"local window = tonumber(ARGV[1])\n" +"local limit = tonumber(ARGV[2])\n" +"local current = redis.call(\"GET\", key)\n" +"if current == false then\n" +"    redis.call(\"SET\", key, 1, \"EX\", window)\n" +"    return 1\n" +"else\n" +"    if tonumber(current) < limit then\n" +"        redis.call(\"INCR\", key)\n" +"        return 1\n" +"    else\n" +"        return 0\n" +"    end\n" +"end";public FixedWindowRateLimiterWithTTL(Jedis jedis, String key, int window, int limit) {this.jedis = jedis;this.key = key;this.window = window;this.limit = limit;}public boolean allowRequest() {Object result = jedis.eval(LUA_SCRIPT, Collections.singletonList(key),Arrays.asList(String.valueOf(window),String.valueOf(limit)));return "1".equals(result.toString());}
}

使用

public static void main(String[] args) {Jedis jedis = new Jedis("localhost");// 创建一个每分钟最多100次请求的限流器FixedWindowRateLimiterWithTTL limiter = new FixedWindowRateLimiterWithTTL(jedis, "api:limit:user1", 60, 100);for (int i = 0; i < 120; i++) {if (limiter.allowRequest()) {System.out.println("处理请求 " + i);} else {System.out.println("限流请求 " + i);}}jedis.close();
}

优点:实现简单
缺点:
固定窗口算法无法解决临界问题
Redis的过期机制是惰性删除+定期删除,可能导致key实际过期时间与预期有微小差异
重启导致的窗口重置
在超高并发下会成为单点瓶颈

http://www.xdnf.cn/news/190837.html

相关文章:

  • 八大排序——直接插入排序/希尔排序
  • Spring Cloud初探之自定义负载均衡策略(五)
  • 让数据优雅落地:用 serde::Deserialize 玩转结构体实体
  • CasaOS上部署1Panel开源运维面板远程在线访问配置实操指南
  • K8s新手系列之K8s中的资源
  • 【杂谈】-人工智能驱动的网络安全威胁:新一代网络钓鱼
  • Azure 数字孪生是什么?
  • ​​HTTP vs HTTPS:传输协议的安全演进与核心差异​
  • 8.Android(通过Manifest配置文件传递数据(meta-data))
  • 近地卫星网络 (Low Earth Orbit Satellite Networks)入门学习笔记
  • Transformer数学推导——Q26 推导多语言Transformer中语言间注意力共享的参数效率公式
  • C语言----操作符详解(万字详解)
  • python 线程池顺序执行
  • 二叉树的所有路径(回溯算法基础)
  • 深度学习---Pytorch概览
  • 3D模型文件格式之《DAE格式介绍》
  • [LeetCode 438/567] 找到字符串中所有字母异位词/字符串的排列(滑动窗口)
  • tsconfig.json的配置项介绍
  • 云原生周刊:Kubernetes v1.33 正式发布
  • 用JavaScript构建3D程序
  • 2025系统架构师---论微服务架构及其应用
  • Linux中的系统延时任务和定时任务与时间同步服务和构建时间同步服务器
  • 老电脑优化全知道(包括软件和硬件优化)
  • 【爬虫】一文掌握 adb 的各种指令(adb备忘清单)
  • 【Mybatis】Mybatis基础
  • 集合框架篇-java集合家族汇总
  • 【3D基础】深入解析OBJ与MTL文件格式:Blender导出模型示例及3D开发应用
  • 【KWDB 创作者计划】_企业数据管理的利刃:技术剖析与应用实践
  • CMake:设置编译C++的版本
  • 【北京】昌平区某附小v3700存储双控故障维修案例