2

我正在设置一个 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 脚本,我将使用 SCRIPT LOAD 并调用 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 键。我尝试使用这个修改后的脚本,它比(1)慢

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

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

2 回答 2

5

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

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

/*
@@ 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怎么样?

于 2013-10-07T15:19:15.060 回答
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)
于 2016-10-10T13:37:00.853 回答