Java Redis多限流

news/2025/1/5 15:42:18/文章来源:https://www.cnblogs.com/mybook000/p/18649909

在现代Web应用中,限流(Rate Limiting)是保护系统资源和防止滥用的重要机制。Redis由于其高性能和原子操作特性,成为实现限流的理想选择。本文将详细介绍如何在Java中使用Redis实现多种限流策略,包括固定窗口限流、滑动窗口限流和令牌桶算法。

一、准备工作

1. 安装Redis

确保Redis已经安装并正在运行。可以通过以下命令安装Redis:

sudo apt-get update
sudo apt-get install redis-server
sudo service redis-server start
​
 
 

2. 添加依赖

在Java项目中使用Redis,推荐使用Jedis库。以下是Maven依赖:

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.6.0</version>
</dependency>
​
 
 

二、固定窗口限流

固定窗口限流是最简单的限流算法。它将时间划分为固定的窗口,每个窗口内限制请求次数。

1. 实现逻辑

每当一个请求到达时,检查当前窗口内的请求数量是否超过限制。如果未超过,则允许请求并增加计数;否则,拒绝请求。

2. 示例代码

import redis.clients.jedis.Jedis;public class FixedWindowRateLimiter {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final int LIMIT = 10; // 每窗口的最大请求数private static final int WINDOW_SIZE = 60; // 窗口大小(秒)private Jedis jedis;public FixedWindowRateLimiter() {this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);}public boolean isAllowed(String userId) {String key = "rate_limit:" + userId;long currentWindow = System.currentTimeMillis() / 1000 / WINDOW_SIZE;String windowKey = key + ":" + currentWindow;if (jedis.exists(windowKey)) {if (Integer.parseInt(jedis.get(windowKey)) < LIMIT) {jedis.incr(windowKey);return true;} else {return false;}} else {jedis.setex(windowKey, WINDOW_SIZE, "1");return true;}}public static void main(String[] args) {FixedWindowRateLimiter limiter = new FixedWindowRateLimiter();String userId = "user123";for (int i = 0; i < 15; i++) {System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));}}
}
​
 
 

三、滑动窗口限流

滑动窗口限流能够更精确地控制请求速率,避免固定窗口算法中临界点的突发流量问题。

1. 实现逻辑

滑动窗口限流记录每个请求的时间戳,并在每次请求时清理过期的记录。

2. 示例代码

import redis.clients.jedis.Jedis;
import java.util.stream.Collectors;
import java.util.List;public class SlidingWindowRateLimiter {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final int LIMIT = 10; // 每窗口的最大请求数private static final int WINDOW_SIZE = 60; // 窗口大小(秒)private Jedis jedis;public SlidingWindowRateLimiter() {this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);}public boolean isAllowed(String userId) {String key = "sliding_rate_limit:" + userId;long currentTime = System.currentTimeMillis() / 1000;long windowStart = currentTime - WINDOW_SIZE;// 清理过期请求jedis.zremrangeByScore(key, 0, windowStart);// 获取当前窗口内的请求数量long count = jedis.zcard(key);if (count < LIMIT) {jedis.zadd(key, currentTime, String.valueOf(currentTime));jedis.expire(key, WINDOW_SIZE);return true;} else {return false;}}public static void main(String[] args) {SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter();String userId = "user123";for (int i = 0; i < 15; i++) {System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));}}
}
​
 
 

四、令牌桶算法

令牌桶算法是一种常用的流量整形算法,能够控制数据的流入速率。

1. 实现逻辑

令牌桶算法通过定时向桶中添加令牌,每次请求消耗一个令牌,如果桶为空则拒绝请求。

2. 示例代码

import redis.clients.jedis.Jedis;public class TokenBucketRateLimiter {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final int MAX_TOKENS = 10; // 最大令牌数private static final int REFILL_RATE = 1; // 每秒添加令牌数private Jedis jedis;public TokenBucketRateLimiter() {this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);}public boolean isAllowed(String userId) {String key = "token_bucket:" + userId;long currentTime = System.currentTimeMillis() / 1000;// 获取最后更新时间和当前令牌数String[] bucketInfo = jedis.hmget(key, "tokens", "timestamp").toArray(new String[0]);int tokens = bucketInfo[0] != null ? Integer.parseInt(bucketInfo[0]) : MAX_TOKENS;long lastRefillTime = bucketInfo[1] != null ? Long.parseLong(bucketInfo[1]) : currentTime;// 计算需要添加的令牌数long timeDiff = currentTime - lastRefillTime;int newTokens = (int) Math.min(MAX_TOKENS, tokens + timeDiff * REFILL_RATE);if (newTokens > 0) {jedis.hmset(key, Map.of("tokens", String.valueOf(newTokens - 1), "timestamp", String.valueOf(currentTime)));jedis.expire(key, MAX_TOKENS / REFILL_RATE); // 设置过期时间return true;} else {return false;}}public static void main(String[] args) {TokenBucketRateLimiter limiter = new TokenBucketRateLimiter();String userId = "user123";for (int i = 0; i < 15; i++) {System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));}}
}
​
 
 

五、总结

通过本文的介绍,我们详细讲解了如何在Java中使用Redis实现三种不同的限流策略:固定窗口限流、滑动窗口限流和令牌桶算法。每种限流策略都有其适用的场景和特点,根据具体需求选择合适的限流策略可以有效保护系统资源和提高服务的稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/863335.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx的referer参数的用法和原理

​ Nginx的referer参数是用于控制HTTP请求中的Referer字段的相关配置。这个参数的主要作用是限制或允许特定来源网站的访问,以加强安全性或控制流量。 用法:限制特定来源网站的访问: 可以使用referer参数来配置Nginx,使其只允许来自指定来源网站的请求。这有助于防止盗链或…

.Net程序员机会来了,微软官方新推出一个面向Windows开发者本地运行AI模型的开源工具

想要开发AI产品的.Net程序员机会来了,这个项目应该好好研究。 虽然说大模型基本都有提供网络API,但肯定没有直接使用本地模型速度快。 最近微软官方新推出AI Dev Gallery开源项目,可以帮助Windows开发人员学习如何将具有本地模型和API的AI添加到Windows应用程序中。01 项目简…

ABB工业机器人SIB-V板维修细节分享

要判断ABB机器人SIB-v板是否需要更换,可以从以下几个方面进行评估: - 检查SIB-v板的状态:查看SIB-v板是否有明显的物理损坏,如烧焦、裂纹或其他损坏迹象。 - 检查连接情况:确保SIB-v板与其他组件的连接牢固,没有松动或腐蚀。 - 检查电池状态:如果SIB-v板上有…

KUKA机械臂驱动器600-20 1X64 UL故障维修细节

库卡机器人作为工业自动化的重要设备,其稳定性和可靠性对于生产线的正常运转至关重要。然而,在使用过程中,KUKA机械臂驱动器故障是不可避免的问题之一。 一、常见KUKA机械手驱动器故障及原因分析 1. 过热故障 过热是常见的库卡工业机器人驱动器600-20 1X64 UL故障之一。这通…

PostgreSQL技术大讲堂 - 第77讲:DB4AI 搭建PG向量数据库AI机器人

PostgreSQL技术大讲堂 - 第77讲,主题:DB4AI 搭建PG向量数据库AI机器人 讲课内容: 1、 向量搜索引擎(PGVector)介绍 2、 向量与Embeddings的定义 3、 向量间的相似度计算方法演示 4、检索增强生成模型(RAG)介绍 5、PG向量数据库+通义千问大模型实现AI机器人 目前主流的关系型…

ABAP excel上传时,数字带文本逗号 转ABAP数量QUAN金额CURR 格式

主要使用 函数MOVE_CHAR_TO_NUM 或者 UNITS_STRING_CONVERT 第二个需要限制客户SU3 参数配置X 或者函数入参默认X, excel导出默认时X格式, 样例参考代码*&---------------------------------------------------------------------* *& Report YWWZ_TEST57 *&…

11 个必备 Docker 工具

​ 1. LazyDocker命令行下的 Docker 管理利器LazyDocker 是一个为命令行用户设计的友好型终端工具,用于管理 Docker 容器、镜像和存储卷。它适合那些习惯于命令行操作但又希望拥有直观界面的用户。 通过 LazyDocker,你可以一站式查看容器的状态、资源消耗、日志等详细信息,并…

大语言模型提示技巧(三)-迭代式提示

大语言模型还没有达到能够准确猜测人类意图的程度,此时它不能立即反馈出令人满意的答复,我们需要做的是对大语言模型进行迭代式提示,反复推进,直至大语言模型给出了令人满意的答案。我们与大语言模型交互时,往往给出的提示过于简略,而大语言模型还没有达到能够准确猜测你…

spring 中 Bean 的生命周期

spring 中 Bean 的生命周期是怎样的?原文 连环18问 https://mp.weixin.qq.com/s/liWn2Dn91cmuiqHSxVO_fASpringBean 生命周期大致分为4个阶段:1.「实例化」,实例化该 Bean 对象2.「填充属性」,给该 Bean 赋值3.「初始化」如果实现了 Aware 接口,会通过其接口获取容器资源如…

一步一步构建RAG智能问答系统

一步一步基于LangChain构建智能问答系统(Construct intelligent question answering system based on LangChain)虽然LLM(大语言模型)非常强大,但它们对于它们未经训练的信息一无所知。如果想使用LLM来回答它未经训练的文档相关问题,我们需要向其提供这些文档的信息。最常…

VSCode开发uni-app环境搭建

为什么选择VS Code?1, HbuilderX对TS类型支持暂不完善2, 前端程序员最熟悉的编辑器3, 支持各种AI插件(比如国内的阿里云通义灵码、百度comate、豆包MarsCode等,国外的也有很多)。安装uni-aap插件(快速创建页面、uni-app代码提示、鼠标悬停查看文档)1, uni-create-vie…