SpringCloud Gateway RequestRateLimiterGatewayFilterFactory RedisRateLimiter

實戰 Spring Cloud Gateway 之限流篇-騰訊雲開發者社區-騰訊雲 (tencent.com)

RedisRateLimiter 限流腳本request_rate_limiter.lua解讀 - 簡書 (jianshu.com)

local tokens_key = KEYS[1]     -- 存放令牌數量的key
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)    -- key的存活時間,如果過了這個時間,肯定就滿了,每必要存了

--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)          --上次取令牌到現在過了多少秒
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 then
  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)

redis.call("setex", tokens_key, ttl, new_tokens)    -- 更新令牌數
redis.call("setex", timestamp_key, ttl, now)      -- 更新最後一次執行時間

return { allowed_num, new_tokens }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章