秦时明月_
2024-08-15
RedisssionRateLimiter的tryAcquireAsync方法中Lua脚本,即滑动窗口限流算法核心实现问题: 不理解下面Lua脚本中加粗代码: 1、为什么会出现令牌总数超过速率,也就是当前剩余令牌和回收的令牌之和大于速率的情况? 2、为什么在令牌总数超过速率情况下,当前剩余令牌数设置为 速率-未过期的记录数,而不是速率-未过期的已发放的令牌数? "local rate = redis.call('hget', KEYS[1], 'rate');" "local interval = redis.call('hget', KEYS[1], 'interval');" "local type = redis.call('hget', KEYS[1], 'type');" "assert(rate ~= false and interval ~= false and type ~= false, 'RateLimiter is not initialized')" "local valueName = KEYS[2];" "local permitsName = KEYS[4];" "if type == '1' then " "valueName = KEYS[3];" "permitsName = KEYS[5];" "end;" "assert(tonumber(rate) >= tonumber(ARGV[1]), 'Requested permits amount could not exceed defined rate'); " "local currentValue = redis.call('get', valueName); " "local res;" "if currentValue ~= false then " "local expiredValues = redis.call('zrangebyscore', permitsName, 0, tonumber(ARGV[2]) - interval); " "local released = 0; " "for i, v in ipairs(expiredValues) do " "local random, permits = struct.unpack('Bc0I', v);" "released = released permits;" "end; " "if released > 0 then " "redis.call('zremrangebyscore', permitsName, 0, tonumber(ARGV[2]) - interval); " "if tonumber(currentValue) released > tonumber(rate) then " "currentValue = tonumber(rate) - redis.call('zcard', permitsName); " "else " "currentValue = tonumber(currentValue) released; " "end; " "redis.call('set', valueName, currentValue);" "end;" "if tonumber(currentValue) < tonumber(ARGV[1]) then " "local firstValue = redis.call('zrange', permitsName, 0, 0, 'withscores'); " "res = 3 interval - (tonumber(ARGV[2]) - tonumber(firstValue[2]));" "else " "redis.call('zadd', permitsName, ARGV[2], struct.pack('Bc0I', string.len(ARGV[3]), ARGV[3], ARGV[1])); " "redis.call('decrby', valueName, ARGV[1]); " "res = nil; " "end; " "else " "redis.call('set', valueName, rate); " "redis.call('zadd', permitsName, ARGV[2], struct.pack('Bc0I', string.len(ARGV[3]), ARGV[3], ARGV[1])); " "redis.call('decrby', valueName, ARGV[1]); " "res = nil; " "end;" "local ttl = redis.call('pttl', KEYS[1]); " "if ttl > 0 then " "redis.call('pexpire', valueName, ttl); " "redis.call('pexpire', permitsName, ttl); " "end; " "return res;", #提问# Java 后端 技术 知识碎片
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP