Redis如何减少lua复制粘贴

3
我正在编写一些redis内部的lua逻辑,几乎每个脚本都有一些共同点。将这些共同点移动到共享函数中会非常方便,但有以下限制:
  1. redis无法使用lua的require语句。
  2. 官方表示不能调用其他redis函数(参见:https://dev59.com/yHzaa4cB1Zd3GeqPPWSk#22599862)。
例如,我在几乎每个地方都有这个代码段。
local prefix = "/" .. type
if typeId then
    prefix = prefix .. "(" .. typeId .. ")"
end

我在考虑在将脚本输入redis之前进行一些后处理,但这似乎有点过度设计...

如何最好地解决/减少这个问题?

更新:

local registryKey = "/counters/set-" .. type
local updatedKey = "/counters/updated/set-" .. type
if typeId then
    redis.call("SAdd", updatedKey, name .. ":" .. typeId)
    redis.call("SAdd", registryKey, name .. ":" .. typeId)
else
    redis.call("SAdd", updatedKey, name)
    redis.call("SAdd", registryKey, name)
end

这是另一个代码示例,它不能轻松地移动到客户端,因为它调用Redis命令,并作为交易的一部分工作。

谢谢!


1
假设有可能共享这个常见的代码片段,你真的想要使用它吗?换句话说,这是一个需要经常完成的平凡任务...将其推入Lua脚本意味着您将使用Redis数据库中的资源来执行可以在其他地方完成的操作。我不是说这是错误的,但通常情况下,我会尽可能将此类逻辑保持在数据库之外。 - Itamar Haber
关于这段代码片段,@itamar-haber 你可能是正确的。但是我有另一个情况,需要使用条件逻辑来触发一遍又一遍的 Redis 命令... 它不能轻易地移动到客户端。 - let4be
另一方面,我可能应该创建另一个具有重复步骤的脚本,并在MULTI内同时使用它们,即MULTI EVALSHA EVALSHA ... 从带宽的角度来看,这似乎并不理想,但不应该是一个大问题。 - let4be
1
每个情况都是不同的 :) 基本上选项有a) 复制粘贴 b) 使用未记录的f_<sha1> 方法或c) “黑客”绕过Redis对全局的保护措施。我觉得(a)最安全。 - Itamar Haber
@ItamarHaber 有两个问题。a)未记录的f_<sha1>方法是什么?b)为什么要在这里使用redis-lua-debugger使用的技巧?(https://github.com/RedisLabs/redis-lua-debugger)(当然,考虑到从不独立运行脚本的从服务器的限制)。 - Ignacio
好的,已添加真正的答案 :) - Itamar Haber
1个回答

4

"黑客" #1

在你使用SCRIPT LOAD加载一些东西后,你会得到一个sha1哈希值,你可以用它来调用EVALSHA中的脚本。同样的sha1值也可以被用于在另一个脚本内部调用该脚本——只需调用函数f_<sha1>。但是,在这种方式下,传递KEYS/ARGV结构的方法有所不同。

需要注意的是,这是未记录的行为,这意味着该行为可能会在Redis的将来版本中发生变化。

感谢Josiah Carlson博士教给我这个技巧,他又把这个技巧归功于其他人(我记得是Fritzy)。有关更多信息,请查看他的lua-call Python包装器:https://github.com/josiahcarlson/lua-call

"黑客" #2

Redis对Lua进行了沙盒处理,并施加了一些限制以保持清晰度。你可以绕过其中的一些限制,例如访问_G并在那里定义你的实用程序函数,这样它将对所有脚本都可用(就像我在https://github.com/redislabs/redis-lua-debugger中所做的那样)。

然而,这也是相当危险的——除了可能存在复制问题外,这种用法未经测试,因此可能会导致未定义的行为(我用我的小脚本成功崩溃了不少实例;))。

P.S.

这两个技巧都需要额外的管理工作,以确保这些“全局”脚本在任何其他脚本调用它们之前被加载。


感谢您详细的回复。我想知道是否最终会添加一种标准化的方式,在Redis实例上提供实用程序代码。我预见自己在许多脚本中反复使用某些代码(例如redis.log包装器、类似underscore.lua的库等)。 - Ignacio
Redis社区始终欢迎建议、想法和PR贡献 - 为什么不提出你的观点并开始讨论呢? - Itamar Haber
Hack #1是否实际上使用了未记录的行为?sha1是客户端获取已加载脚本句柄的唯一方法。(调用f_<sha1>是否有问题?) - Tim Barrass
1
@tim 没错,f_sha1是一个内部实现,你不能指望它在未来版本中保持不变。 - Itamar Haber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接