我只是试图理解Redis/Lua脚本,我想知道是否有人在以下代码中看到了问题。
这是我尝试实现非常简单的"CAS"语义的代码: 只需使用一个键和两个参数调用它。它将检查服务器上与该键关联的值是否以第一个参数开头,如果是,则将键的新值设置为第二个参数并返回1,否则将返回0; 如果该键与除字符串以外的某种类型数据相关联,则Redis将像尝试在此类键/值组合上执行SET命令时一样返回错误。如果在调用之前该键不存在,则函数将返回0(失败)。
以下是脚本:
以下是关于如何在redis-cli中使用前缀值为“bar”调用键“foo”的脚本示例: redis-cli中的命令如下:
我认为这个用法可能是你想要存储"围栏标记(fencing token)"和带有键的值的情况...如果它们持有正确的围栏标记,允许并发客户端尝试更新该值。
这是我尝试实现非常简单的"CAS"语义的代码: 只需使用一个键和两个参数调用它。它将检查服务器上与该键关联的值是否以第一个参数开头,如果是,则将键的新值设置为第二个参数并返回1,否则将返回0; 如果该键与除字符串以外的某种类型数据相关联,则Redis将像尝试在此类键/值组合上执行SET命令时一样返回错误。如果在调用之前该键不存在,则函数将返回0(失败)。
以下是脚本:
local x=string.len(ARGV[1]);
if redis.call('GETRANGE', KEYS[1], 0, x-1) == ARGV[1] then
redis.call('SET', KEYS[1], ARGV[2]);
return 1;
end;
return 0
以下是关于如何在redis-cli中使用前缀值为“bar”调用键“foo”的脚本示例: redis-cli中的命令如下:
eval "local x=string.len(ARGV[1]); if redis.call('GETRANGE', KEYS[1], 0, x-1) == ARGV[1] then redis.call('SET', KEYS[1], ARGV[2]); return 1; end; return 0" 1 foo bar barbazzle
我认为这个用法可能是你想要存储"围栏标记(fencing token)"和带有键的值的情况...如果它们持有正确的围栏标记,允许并发客户端尝试更新该值。
如果没有WATCH / MULTI / EXEC语义,这是否似乎是一种安全的使用模式?(似乎可以获取当前值,在本地代码中分离出围栏标记,构建一个新值,然后随时尝试使用似乎比WATCH / MULTI / EXEC调用更不容易混淆的语义来更新密钥)。
(我知道我的脚本语义与memcached CAS命令略有不同;这是有意的。)
这在我的有限测试中确实通过了...所以我真正想问的是任何潜在的并发/原子性问题以及Lua中是否存在任何愚蠢的问题---因为我几乎从未接触过Lua。