redis限流
前提
redis+lua
滑动窗口
-- 滑动窗口 local key = KEYS[1] local maxSize = ARGV[1] local currentTime = ARGV[2] local startTime = ARGV[3] local uuid = ARGV[4] local currentCount = redis.call('zcount',key,startTime,currentTime) if (currentCount and tonumber(currentCount)>=tonumber(maxSize)) then return 0 end -- 防止zset添加同一时间添加元素覆盖,添加后缀uuid redis.call('zadd',key,currentTime,currentTime..uuid) redis.call('expire',key,60*60*24) -- 删除过期时间区间 redis.call('zremrangebyscore',key,0,startTime-10000) return 1
漏桶
-- 漏桶 -- capacity:容量,passRate:漏水速率,addWater:每次请求加水量(默认为1),water:当前水量,lastTs:时间戳 local limitInfo = redis.call('hmget',KEYS[1],'capacity','passRate','water','lastTs') local capacity = limitInfo[1] local passRate = limitInfo[2] local water = limitInfo[3] local lastTs = limitInfo[4] local addWater = 1 -- 初始化漏桶 if capacity == false or passRate==false then capacity = tonumber(ARGV[1]) passRate = tonumber(ARGV[2]) water = addWater lastTs = ARGV[3] redis.call('hmset',KEYS[1],'capacity',capacity,'passRate',passRate,'addWater',addWater,'water',water,'lastTs',lastTs) return 1 else local nowTs = ARGV[3] -- 当前距离上一次漏水量 local waterPass = tonumber((tonumber(nowTs)-tonumber(lastTs))*tonumber(passRate)/1000) water = math.max(0,tonumber(water-waterPass)) lastTs = nowTs if capacity-water>=addWater then water = water+addWater capacity = tonumber(ARGV[1]) passRate = tonumber(ARGV[2]) redis.call('hmset',KEYS[1],'capacity',capacity,'passRate',passRate,'water',water,'lastTs',lastTs) redis.call('expire',KEYS[1],60*60*24) return 1 end return 0 end
令牌桶
-- 令牌桶 -- capacity:容量,rate:令牌生成速率,leftTokenNum:剩余令牌数,lastTs:时间戳 local limitInfo = redis.call('hmget',KEYS[1],'capacity','rate','leftTokenNum','lastTs') local capacity = limitInfo[1] local rate = limitInfo[2] local leftTokenNum = limitInfo[3] local lastTs = limitInfo[4] -- 本次需要的令牌数 local need = 1 if capacity==false or rate==false or leftTokenNum==false then capacity = tonumber(ARGV[1]) rate = tonumber(ARGV[2]) lastTs = ARGV[3] leftTokenNum = capacity-need redis.call('hmset',KEYS[1],'capacity',capacity,'rate',rate,'leftTokenNum',leftTokenNum,'lastTs',lastTs) return 1 else local nowTs = ARGV[3] -- 距离上次产生的令牌数 local createTokenNum = tonumber((tonumber(nowTs)-tonumber(lastTs))*tonumber(rate)/1000) -- 剩余的令牌数 leftTokenNum = math.min(capacity,createTokenNum+leftTokenNum) lastTs = nowTs -- 判断是否还有令牌 if leftTokenNum>=need then -- 减去需要的令牌 leftTokenNum = leftTokenNum - need -- 更新 capacity = tonumber(ARGV[1]) rate = tonumber(ARGV[2]) redis.call('hmset',KEYS[1],'capacity',capacity,'rate',rate,'leftTokenNum',leftTokenNum,'lastTs',lastTs) redis.call('expire',KEYS[1],60*60*24) return 1 end return 0 end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异