spring-cloud-starter-gateway限流脚本request_rate_limiter.lua分析

1 篇文章 0 订阅
1 篇文章 0 订阅
-- 令牌桶需要两个Redis密钥
local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
--redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key)

-- 每秒产生多少个令牌
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)

--redis.log(redis.LOG_WARNING, "rate " .. ARGV[1])
--redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2])
--redis.log(redis.LOG_WARNING, "now " .. ARGV[3])
--redis.log(redis.LOG_WARNING, "requested " .. ARGV[4])
--redis.log(redis.LOG_WARNING, "filltime " .. fill_time)
--redis.log(redis.LOG_WARNING, "ttl " .. ttl)

-- 剩余的令牌数量
local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil then
  last_tokens = capacity
end
--redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)

-- 上一次的剩余过期时间
local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end
--redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed)

-- 时间间隔 当前时间-上一次的剩余过期时间
local delta = math.max(0, now-last_refreshed)

-- 桶内可用令牌数 = 之前剩余的 + 在delta时间间隔内产生的,最大capacity个
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))

-- 是否允许本次令牌申请,依据是,桶内可用令牌数>=需要获取的令牌数
local allowed = filled_tokens >= requested

-- 需要更新到redis的剩余令牌数
local new_tokens = filled_tokens

-- 本次令牌申请是否成功, 0表示false, 1表示true, 即在java代码中只有当该值为1时, 申请令牌才成功
local allowed_num = 0
if allowed then
-- 如果允许本次令牌的申请, 则剩余令牌数需要减去本次申请的令牌数, 并且设置allowed_num = 1
  new_tokens = filled_tokens - requested
  allowed_num = 1
end

--redis.log(redis.LOG_WARNING, "delta " .. delta)
--redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens)
--redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num)
--redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens)

-- ttl必须>0,(即令牌桶容量)capacity>=rate(每秒产生多少个令牌)
if ttl
 > 0 then
  -- 保存剩余令牌数
  redis.call("setex", tokens_key, ttl, new_tokens)
  -- 保存当前时间戳
  redis.call("setex", timestamp_key, ttl, now)
end

-- 返回本次申请成功标志allowed_num和剩余令牌数new_tokens (注意区分剩余令牌数和本次申请的令牌数)
-- return { allowed_num, new_tokens, capacity, filled_tokens, requested, new_tokens }
return { allowed_num, new_tokens }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值