多租户限流

-- 返回码 1:操作成功 0:未配置 -1: 获取失败 -2:修改错误,建议重新初始化 -500:不支持的操作
-- redis hashmap 中存放的内容:
-- last_mill_second 上次放入令牌或者初始化的时间
-- stored_permits 目前令牌桶中的令牌数量
-- max_permits 令牌桶容量
-- interval 放令牌间隔
-- app 一个标志位,表示对于当前key有没有限流存在
-- filled_tokens=min(max_permits, last_tokens+interval*(max(0,now-last_mill_second))
local SUCCESS = 1
local NO_CONFIG = 0
local ACQUIRE_FAIL = -1
local MODIFY_ERROR = -2
local UNSUPPORT_METHOD = -500
-- 租户私有的令牌参数
local ratelimit_info = redis.pcall("HMGET",KEYS[1], "last_mill_second", "stored_permits", "app_permits", "interval", "app","max_key")
-- 接口最大的流量配置
local max_permits_info = redis.pcall("HMGET",ratelimit_info[6], "max_permits", "interval","stored_max_permits")

local last_mill_second = ratelimit_info[1]
local stored_permits = tonumber(ratelimit_info[2])
local max_permits = tonumber(max_permits_info[1])
local app_permits = tonumber(ratelimit_info[3])
local interval = tonumber(ratelimit_info[4])
local max_interval = tonumber(max_permits_info[2])
local max_stored_permits = tonumber(max_permits_info[3])

local app = ratelimit_info[5]

local method = ARGV[1]
-- ARGV[1] = method
-- ARGV[2] = curr_timestamp
-- ARGV[3] = acquire_permits
-- ARGV[4] = max_permits
-- ARGV[5] = interval
-- ARGV[6] = app
--获取当前毫秒
--考虑主从策略和脚本回放机制,这个time由客户端获取传入
--local curr_time_arr = redis.call('TIME')
--local curr_timestamp = curr_time_arr[1] * 1000 + curr_time_arr[2]/1000
local curr_timestamp = tonumber(ARGV[2])

-- 尝试获取permits
if method == "acquire" then
    --- 标识没有配置令牌桶
    if type(last_mill_second) == 'boolean' or last_mill_second == nil  then
    -- 初始化配置
           redis.pcall("HMSET", KEYS[1],
                "last_mill_second", curr_timestamp,
                "stored_permits", ARGV[4],
                "max_permits", ARGV[4],
                "interval", ARGV[5],
                "app_permits", ARGV[6],
                "app", "default")
      return SUCCESS
    end
    --需要获取令牌数量
    local acquire_permits = tonumber(ARGV[3])
    --计算上一次放令牌到现在的时间间隔中,一共应该放入多少私有令牌
    local reserve_permits = math.max(0, math.floor((curr_timestamp - last_mill_second) / interval))
    --计算上一次放令牌到现在的时间间隔中,一共应该放入多少公有令牌
    local reserve_max_permits = math.max(0, math.floor((curr_timestamp - last_mill_second) / max_interval))
    -- 可以申请的令牌数
    local new_permits = math.min(math.min(max_stored_permits+reserve_max_permits,max_permits),
    stored_permits + reserve_permits)
    local result = ACQUIRE_FAIL
    --如果桶中令牌数量够则放行
    if new_permits >= acquire_permits then
        result = SUCCESS
        new_permits = new_permits - acquire_permits
        new_max_permits = max_permits + reserve_max_permits  - acquire_permits
    end
    --更新当前桶中的令牌数量
    redis.pcall("HSET", KEYS[1], "stored_permits", new_permits)
    redis.pcall("HSET",ratelimit_info[6], "max_permits", new_max_permits)

    --如果这次有放入令牌,则更新时间
    if reserve_permits > 0 then
        redis.pcall("HSET", KEYS[1], "last_mill_second", curr_timestamp)
    end
    return result
end


return UNSUPPORT_METHOD

你可能感兴趣的:(经验总结,redis,java)