这个处理关键过期竞争条件的redis lua脚本是纯函数吗?

usbpc102

我一直在使用redis来跟踪分布式系统中外部api的速率限制。我决定为存在限制的每条路线创建一个密钥。密钥的值是在重置限制之前我仍然可以发出多少个请求。通过将按键的TTL设置为限制将重置的时间来进行重置。

为此,我编写了以下lua脚本:

if redis.call("EXISTS", KEYS[1]) == 1 then
    local remaining = redis.call("DECR", KEYS[1])
    if remaining < 0 then
        local pttl = redis.call("PTTL", KEYS[1])
        if pttl > 0 then
            --[[
            -- We would exceed the limit if we were to do a call now, so let's send back that a limit exists (1)
            -- Also let's send back how much we would have exceeded the ratelimit if we were to ignore it (ramaning)
            -- and how long we need to wait in ms untill we can try again (pttl)
              ]]
            return {1, remaining, pttl}
        elseif pttl == -1 then
            -- The key expired the instant after we checked that it existed, so delete it and say there is no ratelimit
            redis.call("DEL", KEYS[1])
            return {0}
        elseif pttl == -2 then
            -- The key expired the instant after we decreased it by one. So let's just send back that there is no limit
           return  {0}
        end
    else
        -- Great we have a ratelimit, but we did not exceed it yet.
        return {1, remaining}
    end
else
   return {0}
end

由于受监视的密钥可以在多重事务的中间到期而不会中止它我假设lua脚本也是如此。因此,我将ttl为-1或-2的情况放入其中。

写完该脚本后,我在eval命令页面上进行了更深入的研究,发现lua脚本必须是纯函数

在里面说

在给定相同输入数据集的情况下,脚本必须始终使用相同的参数评估相同的Redis写命令。脚本执行的操作不能依赖于任何隐藏的(非显式)信息或状态,这些信息或状态可能随着脚本执行的进行或脚本的不同执行之间的变化而变化,也不能依赖于I / O设备的任何外部输入。

通过此说明,我不确定我的函数是否是纯函数。

usbpc102

在Itamar回答之后,我想为自己确认一下,因此我写了一个lua脚本来测试这一点。脚本创建一个具有10ms TTL的密钥并检查ttl,直到它小于0:

redis.call("SET", KEYS[1], "someVal","PX", 10)
local tmp = redis.call("PTTL", KEYS[1])
while tmp >= 0
do
    tmp = redis.call("PTTL", KEYS[1])
    redis.log(redis.LOG_WARNING, "PTTL:" .. tmp)
end
return 0

当我运行此脚本时,它从未终止。它只是继续向我的日志发送垃圾邮件,直到我杀死了Redis服务器。但是,脚本运行时的时间不会停滞不前,而只是在TTL为0时才停止。

因此,密钥的年龄永远不会过期。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章