用java配合redis 在springboot上实现令牌桶算法
令牌桶算法配合 Redis 在 Java 中的应用令牌桶算法是一种常用的限流算法,适用于控制请求的频率,防止系统过载。结合 Redis 使用可以实现高效的分布式限流。
一.、引入依赖首先,需要在 pom.xml 文件中引入 spring-boot-starter-data-redis 依赖,这个依赖提供了与 Redis 交互的客户端和工具类。
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>
二.、配置 Redis 连接 (我随便用了application.properties ,也可以用 application.yml)
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=2000
三.、实现令牌桶算法
使用 Lua 脚本和 Redis 操作来实现令牌桶算法。在resources创建一个 Lua 脚本文件 request_rate_limiter.lua
-- 获取到限流资源令牌数的key和响应时间戳的key
local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
-- 分别获取填充速率、令牌桶容量、当前时间戳、消耗令牌数
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])
-- 计算出失效时间,大概是令牌桶填满时间的两倍
local fill_time = capacity / rate
local ttl = math.floor(fill_time * 2)
-- 获取到最近一次的剩余令牌数,如果不存在说明令牌桶是满的
local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil thenlast_tokens = capacity
end
-- 上次消耗令牌的时间戳,不存在视为0
local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil thenlast_refreshed = 0
end
-- 计算出间隔时间
local delta = math.max(0, now - last_refreshed)
-- 剩余令牌数量 = “令牌桶容量” 和 “最后令牌数+(填充速率*时间间隔)”之间的最小值
local filled_tokens = math.min(capacity, last_tokens + (delta * rate))
-- 如果剩余令牌数量大于等于消耗令牌的数量则流量通过,否则不通过
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed thennew_tokens = filled_tokens - requestedallowed_num = 1
end
-- 更新令牌桶状态
if ttl > 0 thenredis.call("setex", tokens_key, ttl, new_tokens)redis.call("setex", timestamp_key, ttl, now)
end
return allowed_num
四、创建一个 TokenBucket 类,使用 StringRedisTemplate 执行 Lua 脚本。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;import javax.xml.crypto.Data;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;@Component
public class TokenBucket {private static final String TOKEN_BUCKET_KEY_PREFIX = "rate_limiter:";private static final String LUA_SCRIPT_PATH = "request_rate_limiter.lua";@Autowiredprivate StringRedisTemplate stringRedisTemplate;public boolean tryAccess(String key, int limitCount, int refillRate) {String luaScript = loadLuaScript();// 使用加载的Lua脚本创建一个RedisScript 对象。 DefaultRedisScript 是Spring Data Redis提供的一个类,用于封装Lua脚本。RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);// TOKEN_BUCKET_KEY_PREFIX + key + ":tokens":用于存储令牌桶中的令牌数量。•// TOKEN_BUCKET_KEY_PREFIX + key + ":timestamp":用于存储上一次令牌桶被填充的时间戳。List<String> keys = Arrays.asList(TOKEN_BUCKET_KEY_PREFIX + key + ":tokens", TOKEN_BUCKET_KEY_PREFIX + key + ":timestamp");//执行Lua脚本/*** 使用 StringRedisTemplate 执行Lua脚本。execute方法的参数包括:* • redisScript :Lua脚本对象。* • keys:Redis键列表。* • String.valueOf(refillRate):令牌桶的填充速率。* • String.valueOf(limitCount):令牌桶的最大容量。* • String.valueOf(System.currentTimeMillis() / 1000):当前时间戳(秒级)。* • "1" :请求的令牌数量(这里假设每次请求需要1个令牌)。*/Long result = stringRedisTemplate.execute(redisScript, //Lua脚本对象。keys, //Redis键列表String.valueOf(refillRate), //令牌桶的填充速率String.valueOf(limitCount), //令牌桶的最大容量String.valueOf(System.currentTimeMillis() / 1000), //当前时间戳(秒级)"1" //请求的令牌数量(这里假设每次请求需要1个令牌)。);return result != null && result == 1;}private String loadLuaScript() {InputStreamReader reader = null;try {//使用类加载器从指定路径 LUA_SCRIPT_PATH 获取资源流。我的lua文件在resources根目录下面//使用 InputStreamReader 将输入流 resourceStream 包装成一个字符流,并指定字符编码为UTF-8。这样可以确保读取的文件内容是正确的编码格式reader = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(LUA_SCRIPT_PATH), StandardCharsets.UTF_8);/*创建一个Scanner对象,用于读取字符流。useDelimiter("\\A"):设置分隔符为文件的开始标记 \\A 。这意味着Scanner会将整个文件内容视为一个单一的字符串。next() :读取并返回整个文件内容*/return new java.util.Scanner(reader).useDelimiter("\\A").next();} catch (Exception e) {throw new RuntimeException("Failed to load Lua script", e);}}
}
五、测试
package com.lhx.testany.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class RateLimiterController {@Autowiredprivate TokenBucket tokenBucket;@GetMapping("/test")public String testRateLimiter() {//为了测试,把最多设成2个令牌,每秒只生成1个令牌, 我快速在浏览器调用时,//生成的令牌,不足于被消耗,就会执行esle,这样就能做限流if (tokenBucket.tryAccess("api1", 2, 1)) {return "Request allowed";} else {return "Request denied due to rate limit";}}
}
相关文章:
用java配合redis 在springboot上实现令牌桶算法
令牌桶算法配合 Redis 在 Java 中的应用令牌桶算法是一种常用的限流算法,适用于控制请求的频率,防止系统过载。结合 Redis 使用可以实现高效的分布式限流。 一.、引入依赖首先,需要在 pom.xml 文件中引入 spring-boot-starter-data-re…...
科学计算库NumPy
NumPy是高性能科学计算和数据分析的基础包。 认识NumPy数据对象 n维数组对象ndarray(array) 数组是编程语言中重要且复杂的数据结构,它是由相同类型元素按照一定的顺序排列的集合。ndarray具有矢量算术能力和复杂的广播能力。 - 维度又称为维数,在数学…...
【大数据】机器学习----------强化学习机器学习阶段尾声
一、强化学习的基本概念 注: 圈图与折线图引用知乎博主斜杠青年 1. 任务与奖赏 任务:强化学习的目标是让智能体(agent)在一个环境(environment)中采取一系列行动(actions)以完成一个…...
Unicode不可见字符
场景复现 在访问 https://dotnet.microsoft.com/zh-cn/apps/aspnet地址时 突然出现 https://dotnet.microsoft.com/zh-cn/apps/aspnet%E2%80%8C%E2%80%8C 但是正常来看,这个地址后面是没有%E2%80%8C%E2%80%8C的,粘贴到idea里发现了url地址后面还拼接了2…...
w172二手车交易系统的设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
TRELLIS微软的图生3D
TRELLIS 教程目录: Youtube:https://www.youtube.com/watch?vJqFHZ-dRMhI 官网地址:https://trellis3d.github.io/ GitHub:https://github.com/Microsoft/TRELLIS 部署目录: 克隆项目 git clone --recurse-submodul…...
【力扣:新动计划,编程入门 —— 题解 ①】
向前看,总会有新的故事值得期盼 —— 25.1.21 2235. 两整数相加 给你两个整数 num1 和 num2,返回这两个整数的和。 示例 1: 输入:num1 12, num2 5 输出:17 解释:num1 是 12,num2 是 5 &#x…...
如何使用 Pytest -k 选项轻松筛选测试用例
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 你是否曾不得不从成百上千个测试中费力筛选,只为运行几个特定的测试&am…...
C语言之小型成绩管理系统
🌟 嗨,我是LucianaiB! 🌍 总有人间一两风,填我十万八千梦。 🚀 路漫漫其修远兮,吾将上下而求索。 C语言之小型成绩管理系统 目录 设计题目设计目的设计任务描述设计要求输入和输出要求验收要…...
C++ ——— 模拟实现 vector 类
目录 vector 类的框架 无参数的构造函数 析构函数 获取有效数据个数 获取容量 重载 [] 运算符 可读可写版本 只可读版本 扩容 尾插 实现迭代器 可读可写版本 只可读版本 自定义设置size长度和内容 在任意位置插入 删除任意位置的数据 赋值重载 vector 类的框…...
SpringBoot实现轻量级动态定时任务管控及组件化
1关于动态定时任务 关于在SpringBoot中使用定时任务,大部分都是直接使用SpringBoot的Scheduled注解,如下: Component public class TestTask {Scheduled(cron"0/5 * * * * ? ") //每5秒执行一次public void execute(){SimpleDa…...
STM32 FreeRTOS 任务挂起和恢复---实验
实验目标 学会vTaskSuspend( )、vTaskResume( ) 任务挂起与恢复相关API函数使用: start_task:用来创建其他的三个任务。 task1:实现LED1每500ms闪烁一次。 task2:实现LED2每500ms闪烁一次。 task3:判断按键按下逻辑,KE…...
#漏洞挖掘# 一文了解什么是Jenkins未授权访问!!!
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
1.21学习记录
misc 2023isctf 你说爱我尊嘟假嘟 这题有点脑洞,需要把你说爱我换成Ook.将尊嘟换为Ook!假嘟换成Ook?(根据语气进行猜测吧)用在线工具解密最后用base64解密即可 2023isctf 杰伦可是流量明星 解压后是一个MP3文件&am…...
【Pandas】pandas Series groupby
Pandas2.2 Series Function application, GroupBy & window 方法描述Series.apply()用于将一个函数应用到 Series 的每个元素或整个 SeriesSeries.agg()用于对 Series 数据进行聚合操作Series.aggregate()用于对 Series 数据进行聚合操作Series.transform()用于对 Series…...
Text2SQL 智能报表方案介绍
0 背景 Text2SQL智能报表方案旨在通过自然语言处理(NLP)技术,使用户能够以自然语言的形式提出问题,并自动生成相应的SQL查询,从而获取所需的数据报表,用户可根据得到结果展示分析从而为结论提供支撑&#…...
51c~SLAM~合集1
我自己的原文哦~ https://blog.51cto.com/whaosoft/12327374 #GSLAM 自动驾驶相关~~~ 一个通用的SLAM架构和基准 GSLAM:A General SLAM Framework and Benchmark 开源代码:https://github.com/zdzhaoyong/GSLAM SLAM技术最近取得了许多成功&am…...
服务器安装ESXI7.0系统及通过离线包方式升级到ESXI8.0
新到了一台物理服务器需要安装系统,项目不急用,先拿来做些实验。 本次实验目标: 1、在物理服务器上安装ESXI7.0系统; 2、通过离线包升级方式将ESXI7.0升级为ESXI8.0。 实验环境准备: 物理服务器1台,型号…...
计算机网络 (52)秘钥分配
一、重要性 在计算机网络中,密钥分配是密钥管理中的一个核心问题。由于密码算法通常是公开的,因此网络的安全性主要依赖于密钥的安全保护。密钥分配的目的是确保密钥在传输过程中不被窃取或篡改,同时确保只有合法的用户才能获得密钥。 二、方…...
xctf-comment(Intruder,git恢复,SQL注入,Hex解码)
这题是2018年网鼎杯真题,考察 Burp Suite 的 Intruder 模块去找用户密码,使用 githacker 恢复代码(githack不行),代码审计发现SQL二次注入,尝试SQL注入读取文件内容,读取的是/home/www/.bash_hi…...
Docker Compose创建镜像服务
什么是Docker Compose 使用Docker Compose,可以使用YAML配置文件(称为Compose文件)来配置应用程序的服务,然后使用Compose CLI从配置中创建并启动所有服务 。 Compose文件的默认路径是compose.yaml(首选)…...
kafka学习笔记5 PLAIN认证——筑梦之路
在Kafka中,SASL(Simple Authentication and Security Layer)机制包括三种常见的身份验证方式: SASL/PLAIN认证:含义是简单身份验证和授权层应用程序接口,PLAIN认证是其中一种最简单的用户名、密码认证方式&…...
Walrus Learn to Earn计划正式启动!探索去中心化存储的无限可能
本期 Learn to Earn 活动将带领开发者和区块链爱好者深入探索 Walrus 的技术核心与实际应用,解锁分布式存储的无限可能。参与者不仅能提升技能,还能通过完成任务赢取丰厚奖励!🌊 什么是 Walrus? 数据主权如今正成为越…...
Linux学习笔记
1、什么是Linux Linux,一般指GNU/Linux(单独的Linux内核并不可直接使用,一般搭配GUN套件,故得此称呼),是一种免费使用和自由传播的类UNIX操作系统。它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用…...
解锁电商设计新速度:StartAI插件制作产品图实操教程
在电商设计这片竞争激烈的战场上,每一位设计师都在追求高效与创意的完美融合。繁琐的背景抠图、单一的设计模板、紧迫的时间周期,常常让我们力不从心。但现在,StartAI插件的问世,为我们的设计之路带来了革命性的改变。下面&#x…...
AutoPrompt框架和实操:如何用AutoPrompt完成电影评论和聊天审核任务?
1. AutoPrompt框架概述 1.1 框架定义与目标 AutoPrompt是一个旨在提升和完善用户提示以适应现实世界用例的提示优化框架。该框架通过迭代生成具有挑战性的边缘案例数据集,并相应地优化提示,从而自动生成针对用户意图量身定制的高质量、详细的提示。其核心目标是利用大型语言…...
修复 Kubernetes Deployment 修改后未生效的问题
在 Kubernetes 集群中,当尝试修改某些 Deployment 资源(如 calico-kube-controllers)的 image 配置时,发现修改总是未生效,并恢复到原样。这种问题通常是因为 Deployment 资源受到其他控制器(如 Operator&a…...
Excel 技巧17 - 如何计算倒计时,并添加该倒计时的数据条(★)
本文讲如何计算倒计时,并添加该倒计时的数据条。 1,如何计算倒计时 这里也要用公式 D3 - TODAY() 显示为下面这个样子的 然后右键该单元格,选 设置单元格格式 然后点 常规 这样就能显示出还书倒计时的日数了。 下拉适用到其他单元格。 2&a…...
Golang Gin系列-5:数据模型和数据库
在这篇Gin教程的博客中,我们将探索如何将模型和数据库与Gin框架无缝集成,使你能够构建健壮且可扩展的web应用程序。通过利用流行的库并遵循最佳实践,你将学习如何定义模型、建立数据库连接、执行CRUD操作以及确保基于gin的项目中的数据完整性…...
Android系统开发(十九):无缝拉伸的艺术——9-Patch 可绘制对象详解
引言 在移动开发中,背景、标题以及其他界面元素的设计质量直接影响用户体验。然而,如何让图片适应不同分辨率设备,成为开发者常常头疼的问题。这时,9-Patch 闪亮登场!它不仅可以无缝拉伸,还能保持视觉效果…...
物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境:飞腾派开发板(国产E2000处理器) 软件环境:飞腾派OS(Phytium Pi OS) 硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板…...
计算机网络 (51)鉴别
前言 计算机网络鉴别是信息安全领域中的一项关键技术,主要用于验证用户或信息的真实性,以及确保信息的完整性和来源的可靠性。 一、目的与重要性 鉴别的目的是验明用户或信息的正身,对实体声称的身份进行唯一识别,以便验证其访问请…...
Mellanox ConnectX 系列网卡的双驱动架构:以太网与 InfiniBand 的协同设计
在现代数据中心和高性能计算(HPC)环境中,网络硬件的性能和功能至关重要。Mellanox ConnectX 系列网卡以其卓越的性能和多功能性而闻名,支持从传统的以太网到高性能的 InfiniBand 网络协议。这种多功能性使得 Mellanox 网卡能够满足不同应用场景的需求,从常规的数据中心网络…...
【Java】阿里环球Antom支付对接
阿里环球Antom支付对接 线上文档地址: GitHub:https://github.com/alipay/global-open-sdk-java 文档:https://global.alipay.com/docs/ac/ams_zh-cn/session_cashier maven: <!--阿里国际支付--><dependency><g…...
【vim】vim编辑器如何设置行号
vim编辑器如何设置行号 一、**临时设置行号**二、永久设置行号2.1. **用户配置文件方式(针对当前用户)**2.2. **全局配置文件方式(谨慎使用,会影响所有用户)** 在Vim中设置行号有以下两种常见的方法: 一、…...
爬虫基础之爬取某站视频
目标网址:为了1/4螺口买小米SU7,开了一个月,它值吗?_哔哩哔哩_bilibili 本案例所使用到的模块 requests (发送HTTP请求)subprocess(执行系统命令)re (正则表达式操作)json (处理JSON数据) 需求分析: 视频的名称 F12 打开开发者工具 or 右击…...
2024嵌入式系统的未来发展与技术洞察分享
时间如白驹过隙,不知不觉又是一年,这一年收获满满。接下来,将本年度对技术的感悟和洞察分析如下,希望对大家有所帮助。 在过去几十年里,嵌入式系统技术迅速发展,成为现代电子设备和智能硬件的核心组成部分。…...
[微服务]注册中心优化
环境隔离 企业实际开发中,往往会搭建多个运行环境,例如: 开发环境测试环境预发布环境生产环境 这些不同环境之间的服务和数据之间需要隔离。 还有的企业中,会开发多个项目,共享nacos集群。此时,这些项目…...
Leetcode 3426. Manhattan Distances of All Arrangements of Pieces
Leetcode 3426. Manhattan Distances of All Arrangements of Pieces 1. 解题思路2. 代码实现 题目链接:3426. Manhattan Distances of All Arrangements of Pieces 1. 解题思路 这道题很惭愧,一开始没有搞定,后来看了答案想了想ÿ…...
【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评
标题中的“最新重庆市乡镇界面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移最新”指的是一个地理信息系统(GIS)的数据集,特别设计用于ArcGIS软件。这个数据集包含了重庆市所有乡镇的边界信息,以Shapefile(.shp…...
基于ChatGPT的论文写作辅助工具研究
**基于ChatGPT的论文写作辅助工具研究** **摘要**: 随着人工智能技术的飞速发展,自然语言处理(NLP)领域取得了显著进步。ChatGPT作为OpenAI最新推出的生成式预训练Transformer模型,在文本生成、对话系统等方面展现出…...
定时器setTimeout和setInterval
setTimeOut()异步 setInterval()异步...
PCL 部分点云视点问题【2025最新版】
目录 一、问题概述二、解决方案1、软件实现2、代码实现三、调整之后博客长期更新,本文最近更新时间为:2025年1月18日。 一、问题概述 针对CloudCompare软件处理过的pcd格式点云,在使用PCL进行特征点提取、配准等实验中最终显示结果出现点云位置偏差较大的问题,本博客给出解…...
Cursor 与常见集成开发环境(IDE)的优势对比
Cursor与常见集成开发环境(IDE)的优势对比 一、AI 辅助编程能力 强大的代码生成功能: Cursor: 以其内置的强大 AI 辅助编程功能为核心优势。用户可以通过输入自然语言描述,快速生成各种编程语言的代码。例如…...
TDengine 做为 FLINK 数据源技术参考手册
Apache Flink 是一款由 Apache 软件基金会支持的开源分布式流批一体化处理框架,可用于流处理、批处理、复杂事件处理、实时数据仓库构建及为机器学习提供实时数据支持等诸多大数据处理场景。与此同时,Flink 拥有丰富的连接器与各类工具,可对接…...
不重启JVM,替换掉已经加载的类
不重启JVM,替换掉已经加载的类 直接操作字节码 使用ASM框架直接操作class文件,在类中修改代码,然后retransform就可以了 下边是BTrace官方提供的一个简单例子: package com.sun.btrace.samples;import com.sun.btrace.annotati…...
axios的使用总结
一、Axios 简介 Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。在 Vue 项目中,它主要用于发送 HTTP 请求来获取数据(如从 API 获取数据)或者提交数据(如用户登录、注册等表单数据)。 二…...
使用 F12 查看 Network 及数据格式
在浏览器中,F12 开发者工具的 “Network” 面板是用于查看网页在加载过程中发起的所有网络请求,包括 API 请求,以及查看这些请求的详细信息和响应数据的。以下以常见的 Chrome 浏览器为例,介绍如何使用 F12 控制台查看 Network 里…...
HTML<img>标签
例子 如何插入图片: <img src"img_girl.jpg" alt"Girl in a jacket" width"500" height"600"> 下面有更多“自己尝试”的示例。 定义和用法 该<img>标签用于在 HTML 页面中嵌入图像。 从技术上讲&#x…...
Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普
引言: 今天我们聊聊Android生态中最“硬核”的话题:通用内核镜像(GKI)与内核模块接口(KMI)。这是内核碎片化终结者的秘密武器,解决了内核和供应商模块之间无尽的兼容性问题。为什么重要&#x…...