如何避免Redis调用Lua脚本限制?

时间:2013-10-05 20:25:37

标签: lua redis

我正在设置一个PHP标记的缓存实现,它将同时使用Redis和APCu。 由于APC是键值存储,我将使用Redis进行密钥标记关系并与APC上的每个Web服务器同步。

我目前的问题只涉及Redis。 可能你知道实现,但要明确:密钥可以有与之关联的标签。在稍后的某个时间点,您可以通过某些标记删除缓存的密钥。 有许多键而不是很多标签,键和标签之间存在n对n的关系。

set(key, value, tags)包含:

SET key value
foreach tag in tags
    SADD tag key

因为在设置之后不需要检索或更改标签,所以我只需要保持标签到密钥的关系。

deleteByTag(tags)

keys = SUNION tag1 tag2 tag3...
DEL key1 key2 key2...

为了加快速度,我创建了2个简单的lua脚本,我将脚本加载并调用EVALSHA。

Lua 设置脚本:

redis.call('set', KEYS[1], KEYS[2])
for _, tag in pairs(ARGV) do
    redis.call('sadd', tag, KEYS[1])
end

调用
EVALSHA setHash 2 key value tag1 tag2 tag3...

deleteByTag 脚本我遇到这样的问题:

redis.call('del', unpack(redis.call('sunion', unpack(ARGV))))
redis.call('del', unpack(ARGV))

调用
EVALSHA deleteByTagHash 0 tag1 tag2 tag3...

一切都很好,除非redis.call('sunion', unpack(ARGV))返回了很多键。似乎Lua对方法可以拥有的参数数量有一个硬性限制。在我的环境中它是8000 我想知道是否有办法通过标签清除密钥但是避免:

  • (1)往返服务器并往返传送密钥到客户端
  • (2)for-each on keys。我尝试使用这个修改过的脚本,它比(1)

这是(2)不够快的工作:

for _, key in pairs(redis.call('sunion', unpack(ARGV))) do
    redis.call('del', key)
end
redis.call('del', unpack(ARGV))

2 个答案:

答案 0 :(得分:5)

我几乎可以肯定,您可以通过更改环境8000中的LUAI_MAXCSTACK值并重建它(Lua环境)来增加该数字(luaconf.h)。

默认值是,正如您已经注意到的那样:

/*
@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
@* can use.
** CHANGE it if you need lots of (Lua) stack space for your C
** functions. This limit is arbitrary; its only purpose is to stop C
** functions to consume unlimited stack space. (must be smaller than
** -LUA_REGISTRYINDEX)
*/
#define LUAI_MAXCSTACK  8000

只有它像色情片一样接缝。

如何使用表并迭代table.concat()<=8000个密钥块?

答案 1 :(得分:3)

有同样的问题并用Lua函数解决了它:

local call_in_chunks = function (command, args)
    local step = 1000
    for i = 1, #args, step do
        redis.call(command, unpack(args, i, math.min(i + step - 1, #args)))
    end
end

call_in_chunks('del', keys)