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
复制代码

 

posted @   多少幅度  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示