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

lua脚本实现Redis令牌桶限流

背景

令牌桶限流是一种常见的流量控制算法,用于控制系统的请求处理速率,防止系统过载。在令牌桶限流算法中,可以将请求看作是令牌,而令牌桶则表示系统的处理能力。系统在处理请求时,首先需要从令牌桶中获取令牌,如果令牌桶中没有足够的令牌,就需要等待一定时间,直到令牌桶中有足够的令牌。
具体来说,令牌桶限流算法可以通过以下方式实现:
1.系统维护一个固定容量的令牌桶,每秒钟会向桶中添加一定数量的令牌,直到桶的容量达到上限。
2.每次请求来临时,需要先从令牌桶中获取令牌,如果桶中有足够的令牌,则请求被允许通过,并从桶中移除一个令牌;如果桶中的令牌数量不足,则请求被拒绝。具体来说,令牌桶算法会维护一个令牌桶,其中包含一定数量的令牌,每个令牌代表一个可以执行操作的许可。在每个时间段内,如果有令牌可用,就可以执行一个操作,并将令牌桶中的令牌数量减少一。如果没有令牌可用,就不能执行操作,需要等待一定时间,直到令牌桶中有足够的令牌。
3.由于令牌桶的容量是有限的,因此当桶中的令牌数量达到上限时,新的令牌会被丢弃,从而限制了请求的处理速率。
令牌桶限流算法可以在多种场景中进行流量控制,例如 Web 应用程序、消息队列、数据库等。在 Web 应用程序中,可以通过令牌桶限流算法控制 API 的访问速率,防止 API 被恶意攻击或者过载。在消息队列中,可以通过令牌桶限流算法控制消息的生产和消费速率,防止消息堆积和系统崩溃。在数据库中,可以通过令牌桶限流算法控制查询和写入操作的速率,防止数据库过载和响应时间过长。

lua脚本实现令牌桶算法

Lua 脚本可以用来实现 Redis 的令牌桶限流:
1.定义 Redis 数据结构
使用 Redis 的 Hash 数据结构存储当前令牌桶的状态。在 Hash 中,rate 表示速率(每秒生成的令牌数),capacity 表示桶的容量(最多可以同时存储的令牌数),tokens 表示当前桶中的令牌数量,timestamp 表示上次更新令牌数量的时间戳。示例代码:

HSET rdb:token_bucket rate 10 capacity 100 tokens 100 timestamp 0

2.编写 Lua 脚本
编写 Lua 脚本来实现限流逻辑。在脚本中,首先读取当前时间戳和桶的状态,计算出从上次更新时间戳到当前时间应该生成的令牌数量。然后,将当前桶中的令牌数量和应该生成的令牌数量相加,得到当前桶中的令牌数量。如果当前桶中的令牌数量超过了桶的容量,将其限制为桶的容量。
然后,判断当前桶中的令牌数量是否足够执行操作。如果令牌数量足够,将当前桶中的令牌数量减去操作所需的令牌数量,并更新桶的状态。如果令牌数量不足,则返回限流的错误信息。
示例代码:

-- 读取桶的状态
local rate = tonumber(redis.call('HGET', KEYS[1], 'rate'))
local capacity = tonumber(redis.call('HGET', KEYS[1], 'capacity'))
local tokens = tonumber(redis.call('HGET', KEYS[1], 'tokens'))
local timestamp = tonumber(redis.call('HGET', KEYS[1], 'timestamp'))-- 计算应该生成的令牌数量
local now = redis.call('TIME')
local elapsed = now[1] - timestamp
local generated = math.floor(elapsed * rate)-- 更新令牌数量并限制桶的容量
tokens = math.min(capacity, tokens + generated)-- 执行操作
local required = tonumber(ARGV[1])
if tokens >= required thentokens = tokens - requiredredis.call('HSET', KEYS[1], 'tokens', tokens)redis.call('HSET', KEYS[1], 'timestamp', now[1])return 1
elsereturn 0
end

3.在应用程序中调用 Lua 脚本
在应用程序中,使用 Redis 的 EVAL 命令来调用 Lua 脚本。示例代码:

@Component
public class TokenBucketLimiter {@Autowiredprivate RedisTemplate<String, String> redisTemplate;public boolean tryAcquire(String key, int tokens) {List<String> keys = Arrays.asList(key);List<String> args = Arrays.asList(Integer.toString(tokens));Long result = redisTemplate.execute(new DefaultRedisScript<>("local rate = tonumber(redis.call('HGET', KEYS[1], 'rate')) " +"local capacity = tonumber(redis.call('HGET', KEYS[1], 'capacity')) " +"local tokens = tonumber(redis.call('HGET', KEYS[1], 'tokens')) " +"local timestamp = tonumber(redis.call('HGET', KEYS[1], 'timestamp')) " +"local now = redis.call('TIME') " +"local elapsed = now[1] - timestamp " +"local generated = math.floor(elapsed * rate) " +"tokens = math.min(capacity, tokens + generated) " +"if tokens >= tonumber(ARGV[1]) then " +"    tokens = tokens - tonumber(ARGV[1]) " +"    redis.call('HSET', KEYS[1], 'tokens', tokens) " +"    redis.call('HSET', KEYS[1], 'timestamp', now[1]) " +"    return 1 " +"else " +"    return 0 " +"end",Long.class), keys, args);return result != null && result == 1L;}
}

或者如下脚本:

-- 返回码 1:通过限流 0:不通过
-- rate ARGV[1] 每秒填充速率
-- now  ARGV[2] 当前时间
-- capacity ARGV[3] 令牌桶最大数量
-- request ARGV[4] 需要令牌数量
local SUCCESS = "1"
local FAIL = "0"
local rate = tonumber(ARGV[1]) -- replenishRate 令令牌桶填充平均速率
local capacity = tonumber(ARGV[2]) -- burstCapacity 令牌桶上限
local now = tonumber(ARGV[3]) -- 机器传入的当前时间 秒
local requested = tonumber(ARGV[4]) -- 消耗令牌数量,默认取1local fill_time = capacity/rate   -- 计算令牌桶填充满令牌需要多久时间
local ttl = math.floor(fill_time*2) -- *2 保证时间充足local result = SUCCESS;-- ttl 防止小于0
if ttl < 1 thenttl = 10
end-- 1、获取桶内令牌剩余数量
local last_tokens = tonumber(redis.call("get", KEYS[1]))
-- 获得令牌桶剩余令牌数
if last_tokens == nil then -- 第一次时,没有数值,所以桶时满的last_tokens = capacity
end-- 2、获取上次更新时间
local last_refreshed = tonumber(redis.call("get", KEYS[2]))
-- 令牌桶最后填充令牌时间
if last_refreshed == nil thenlast_refreshed = 0
end-- 3、本次验证和上次更新时间的间隔
local delta = math.max(0, now-last_refreshed)
-- 填充令牌,计算新的令牌桶剩余令牌数 填充不超过令牌桶令牌上限。
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))-- 4、判断令牌数量是否足够
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = "0"
if allowed then-- 若成功,令牌桶剩余令牌数(new_tokens) 减消耗令牌数( requested ),并设置获取成功( allowed_num = 1 ) 。new_tokens = filled_tokens - requestedallowed_num = SUCCESS
end-- 5、设置令牌桶剩余令牌数( new_tokens ) ,令牌桶最后填充令牌时间(now) ttl是超时时间
redis.call("setex", KEYS[1], ttl, new_tokens)
redis.call("setex", KEYS[2], ttl, now)if not allowed thenreturn FAIL
endreturn SUCCESS

相关文章:

lua脚本实现Redis令牌桶限流

背景 令牌桶限流是一种常见的流量控制算法&#xff0c;用于控制系统的请求处理速率&#xff0c;防止系统过载。在令牌桶限流算法中&#xff0c;可以将请求看作是令牌&#xff0c;而令牌桶则表示系统的处理能力。系统在处理请求时&#xff0c;首先需要从令牌桶中获取令牌&#…...

最新 23 届计算机校招薪资汇总

24 届的秋招提前批已经开始了&#xff0c;比如米哈游、oppoe、tplink 等公司都已经录取开启提前批。 像腾讯、字节、阿里等一线大厂的话&#xff0c;根据往年的情况&#xff0c;估计是 7月下-8 月初。 所以今年参加秋招的同学&#xff0c;要抓紧复习了。 提前批通常就持续不到…...

BUU CODE REVIEW 1

BUU CODE REVIEW 1 考点&#xff1a;PHP变量引用 源码直接给了 <?phphighlight_file(__FILE__);class BUU {public $correct "";public $input "";public function __destruct() {try {$this->correct base64_encode(uniqid());if($this->c…...

django使用ztree实现树状结构效果,子节点实现动态加载(l懒加载)

一、实现的效果 由于最近项目中需要实现树状结构的效果,考虑到ztree这个组件大家用的比较多,因此打算在django项目中集成ztree来实现树状的效果。最终实现的示例效果如下: 点击父节点,如果有子节点,则从后台动态请求数据,然后显示出子节点的数据。 二、实现思路 …...

认识springboot 之 了解它的日志 -4

前言 本篇介绍springboot的日志&#xff0c;如何认识日志&#xff0c;如何进行日志持久化&#xff0c;通过日志级别判断信息&#xff0c;了解Lombok插件的使用&#xff0c;通过Lombok自带注释更简洁的来完成日志打印&#xff0c;如有错误&#xff0c;请在评论区指正&#xff0…...

关于大规模数据处理的解决方案

大规模数据处理已经成为了现代商业和科学的核心。随着互联网普及和物联网技术的发展&#xff0c;越来越多的数据被收集和存储&#xff0c;这些数据包含了各种各样的信息&#xff0c;例如客户行为、传感器读数、社交媒体活动等等。这些数据的数量和复杂性已经超出了传统数据处理…...

免费快速下载省市区县行政区的Shp数据

摘要&#xff1a;一般非专业的GIS应用通常会用到省市等行政区区划边界空间数据做分析&#xff0c;本文简单介绍了如何在互联网上下载省&#xff0c;市&#xff0c;区县的shp格式空间边界数据&#xff0c;并介绍了一个好用的在线数据转换工具&#xff0c;并且开源。 一、首先&am…...

MAC下配置android-sdk

MAC下配置android-sdk 1、前提2、brew安装3、配置sdk 1、前提 安装好JDK安装brew 2、brew安装 brew install android-sdk brew install android-platform-tools检查是否安装成功 android3、配置sdk brew list android-sdk进入配置文件 sudo vim ~/.zshrc配置 export AND…...

Hive-数据倾斜

在计算各省份的GMV时&#xff0c;有可能会发生数据倾斜&#xff0c;解决办法如下&#xff1a; 分组聚合 预聚合思想 map-side&#xff08;预聚合在map里面&#xff09;skew-groupby&#xff08;多个reduce阶段进行汇总&#xff09;&#xff1a;先对倾斜的key加上随机数&#x…...

Java多线程(三)

目录 一、Thread类基本用法 1.1 Thread常见构造方法 1.2 Thread常见属性 二、多线程常用的创建方式 2.1 继承Thread类 2.2 实现Runnable接口 2.3 继承Thread接口&#xff0c;使用匿名内部类 2.4实现Runnable接口&#xff0c;使用匿名内部类 2.5使用lambda表达式 三、线程的启动…...

Linux操作系统3-项目部署

手动部署 步骤 1.在idea中将文件项目进行打包 2.自定义一个文件目录&#xff0c;上传到Linux 3.使用 java -jar jar包名就可以进行运行 注意,如果需要启动该项目&#xff0c;需要确定所需的端口是否打开 采用这种方式&#xff0c;程序运行的时候会出现霸屏&#xff0c;并且会…...

软件测试面试题——接口自动化测试怎么做?

面试过程中&#xff0c;也问了该问题&#xff0c;以下是自己的回答&#xff1a; 接口自动化测试&#xff0c;之前做过&#xff0c;第一个版本是用jmeter 做的&#xff0c;1 主要是将P0级别的功能接口梳理出来&#xff0c;根据业务流抓包获取相关接口&#xff0c;并在jmeter中跑…...

如何在医疗器械行业运用IPD?

医疗器械是指单独或者组合使用于人体的仪器、设备、器具、材料或其他物品&#xff0c;包括所需要的软件。按安全性可分为低风险器械、中风险器械和高风险器械。其中低风险器械大都属于低值耗材&#xff0c;其中包括绷带、纱布、海绵、消毒液等&#xff1b;中度风险器械类包括体…...

16. Spring Boot 统一功能处理

目录 1. 用户登录权限校验 1.1 最初用户登录验证 1.2 Spring AOP 用户统一登陆验证 1.3 Spring 拦截器 1.3.1 创建自定义拦截器 1.3.2 将自定义拦截器加入系统配置 1.4 练习&#xff1a;登录拦截器 1.5 拦截器实现原理 1.6 统一访问前缀添加 2. 统一异常处理 3. 统…...

PostgreSQL-数据库命令

PostgreSQL-数据库命令 介绍 一个数据库是一个或多个模式的集合,而模式包含表、函数等。因此,完整的逻辑组织结构层次是服务器实例(PostgreSQL Server)、数据库(Database)、模式(Schema)、表(Table),以及某些其他对象(如函数)。一个PostgreSQL服务器实例可以管理…...

面试题:说说JavaScript中内存泄漏的几种情况?垃圾回收机制

内存泄漏 一、是什么&#xff1f;二、垃圾回收机制&#xff1f;2.1、标记清除法2.2、引用计数法 三、常见内存泄露情况 一、是什么&#xff1f; 由于疏忽或错误造成程序未能释放已经不再使用的内存&#xff1b;并非指内存在物理上的消失&#xff0c;而是应用程序分配某段内存后…...

HTML基础介绍1

HTML是什么 1.HTML&#xff08;HyperText Mark-up Language&#xff09;即超文本标签语言&#xff08;可以展示的内容类型很多&#xff09; 2.HTML文本是由HTML标签组成的文本&#xff0c;可以包括文字、图形、动画、声音、表格、连接等 3.HTML的结构包括头部&#xff08;He…...

【腾讯云 Cloud Studio 实战训练营】Redisgo_task 分布式锁实现

文章目录 前言问题场景腾讯云 Cloud Studio Redisgo_task长短类型分布式场景介绍Redisgo_task实现原理SetNx(valueexpire)原子性子协程Done()时间点子协程中的Ticker Redisgo_task唯一外部依赖Redisgo_task Lock结构Redisgo_task架构健壮性设计Redisgo_task可扩展性Redisgo_tas…...

Linux CentOS系统怎么下载软件

Linux CenOS系统想要下载软件可以在Linux内置的应用商店&#xff0c;并通过Yum 包管理器来下载&#xff08;直接使用yum命令下载软件&#xff09; 在Linux系统中&#xff0c;Yum&#xff08;Yellowdog Updater, Modified&#xff09;是用于管理RPM软件包的一个包管理器。 安装…...

SNAT和DNAT原理与应用

iptables的备份和还原 1.写在命令行当中的都是临时配置。 2.把我们的规则配置在 备份&#xff08;导出&#xff09;&#xff1a;iptables-save > /opt/iptables.bak 默认配置文件&#xff1a;/etc/sysconfig/iptables 永久配置&#xff1a;cat /opt/iptables.bak > /etc…...

毕业答辩效率突围!Paperxie AI 一键搞定高质量毕业论文PPT

paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPThttps://www.paperxie.cn/ppt/createhttps://www.paperxie.cn/ppt/create 每一年毕业季&#xff0c;绝大多数高校学生都会陷入同一个困境&#xff1a;论文定稿万事俱备&#xff0c;却卡在了毕业论文答…...

CVPR 2023五大技术断层:泛化性、实时性与边缘部署的工程真相

1. 这不是会议速记&#xff0c;而是一份“CVPR 2023技术脉络手绘地图”如果你在搜索引擎里输入“CVPR 2023 summary”&#xff0c;大概率会看到一堆标题党文章&#xff1a;什么“十大突破”、什么“最火模型TOP5”、什么“必看论文清单”。我翻过不下二十篇&#xff0c;结果发现…...

Generative AI落地四层架构与企业级避坑指南

1. 这不是“AI画画”或“AI写文案”——它是一场底层认知范式的迁移Generative AI&#xff0c;这个词现在几乎天天刷屏&#xff0c;但很多人点开一篇介绍&#xff0c;看到的还是“用MidJourney生成海报”“让ChatGPT写周报”这类表层操作。这就像当年第一次听说“互联网”&…...

KMS_VL_ALL_AIO:告别激活烦恼的完整解决方案指南

KMS_VL_ALL_AIO&#xff1a;告别激活烦恼的完整解决方案指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否曾经为了激活Windows系统而花费数小时研究复杂的命令行&#xff1f;或者面对O…...

【AI Agent部署】Claude Code + Ollama/CC Switch 部署指南

Windows11 Claude Code 简单的配置指南方式一和方式二中也是两种Claude Code的安装方式 方式一&#xff1a;NPM 全局安装 依赖Node环境适合原本就用Node开发的用户容易出现全局包路径冲突 方式二&#xff1a;Winget 原生安装&#xff08;推荐新方案&#xff09; 无任何依赖&am…...

重塑AI代理的数据智能:Wren AI如何构建开放上下文层

重塑AI代理的数据智能&#xff1a;Wren AI如何构建开放上下文层 【免费下载链接】WrenAI Turn any AI Agents into world-class data analysts through the open context layer that gives AI agents grounded, governed memory, context, SQL across 20 data sources, that he…...

Three.js实战:3D数据可视化入门与实践

Three.js实战&#xff1a;3D数据可视化入门与实践 前言 大家好&#xff0c;我是前端老炮儿。今天咱们来聊聊Three.js&#xff01; 在数据可视化领域&#xff0c;3D可视化正变得越来越重要。Three.js作为一个强大的3D库&#xff0c;可以帮助我们轻松创建各种3D效果。 今天我就带…...

乡村景区智慧垂钓破局增收!巨有科技激活乡村“渔乐”经济

垂钓作为国民级休闲活动&#xff0c;拥有超1.2亿爱好者&#xff0c;是乡村文旅中极具潜力的黄金业态。然而&#xff0c;多数乡村钓场仍停留在“一根竿、一个塘”的粗放运营阶段&#xff0c;面临计费混乱、管理成本高、体验同质化、增收乏力等困境。巨有科技聚焦乡村场景&#x…...

Scarab终极教程:2024年最完整的空洞骑士模组管理器使用指南

Scarab终极教程&#xff1a;2024年最完整的空洞骑士模组管理器使用指南 【免费下载链接】Scarab An installer for Hollow Knight mods written with Avalonia. 项目地址: https://gitcode.com/gh_mirrors/sc/Scarab 还在为空洞骑士模组安装而烦恼吗&#xff1f;Scarab模…...

苹果M1/M2芯片跑自监督学习:统一内存与Metal后端实战指南

1. 项目概述&#xff1a;为什么苹果自研芯片正在悄悄改写AI训练的底层逻辑最近三个月&#xff0c;我陆续在三台不同配置的Mac上跑通了SimCLR、BYOL和MoCo v3这三套主流自监督学习&#xff08;SSL&#xff09;模型的完整训练流程——不是跑个demo&#xff0c;而是用ImageNet-1K子…...