Redis Lua脚本实现CAS(检查并设置)? [英] Redis Lua script implementing CAS (check-and-set)?

查看:389
本文介绍了Redis Lua脚本实现CAS(检查并设置)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想了解Redis/Lua脚本,我想知道是否有人看到以下代码有问题.

I'm just trying to understand Redis/Lua scripting and I want to know if anyone sees a problem with the following code.

这是我尝试实现非常简单的"CAS"语义的尝试:使用单个键和两个参数来调用它.它将检查服务器上与该键关联的值是否以第一个参数开头,如果是,则将设置键的新值设置为第二个参数并返回1,否则返回0;如果键与字符串以外的其他某种类型的数据相关联,则Redis将返回并返回错误,就像您尝试对这样的键/值组合使用SET命令一样.如果该键在调用之前不存在,则该函数将返回0(失败).

It's my attempt to implement very simple "CAS" semantics: call it with a single key and two arguments. It will check to see if the value associated with that key on the server starts with first argument and, if it does, will set set the key's new value to the second argument and return 1 otherwise it will return 0; if the key is associated with some type of data other than a string then Redis will return and error just as it would if you attempted a SET command on such a key/value combination. If the key doesn't exist prior to the call then the function will return 0 (failure).

这是脚本:

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

下面是一个在前缀为"bar"(在 redis-cli 中)的键"foo"上调用脚本的示例:

Here's an example of calling the script on a key "foo" with a prefix value of "bar" (in the 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

我认为这种用法模式可能是您想同时存储围栏令牌"和带有键的值的情况……如果并发客户端持有正确的围栏,则允许并发客户端尝试更新该值令牌.

I think the usage pattern for this might be cases where you want to store both a "fencing token" and a value with a key ... allowing concurrent clients to attempt updates to the value if they're holding the correct fencing token.

这似乎代替WATCH/MULTI/EXEC语义是一种安全的使用模式吗? (似乎您可以获取当前值,在本地代码中拆分防护令牌,构建一个新值,然后尝试在任何时候使用比WATCH/MULTI/EXEC调用看起来更容易混淆的语义尝试更新密钥).

Does this seem like it would be a safe usage pattern in lieu of WATCH/MULTI/EXEC semantics? (Seems like you can fetch the current value, split off the fencing token in your local code, build a new value and then try to update the key anytime you like with semantics that seem less confusing than the WATCH/MULTI/EXEC calls).

(我知道我的脚本的语义与 memcached CAS命令略有不同;这是有意的).

(I'm aware that the semantics of my script differ slightly from the memcached CAS command; that's intentional).

这确实通过了我的有限测试...所以我真的是在问任何潜在的并发/原子性问题,以及Lua中是否有任何愚蠢的东西---因为我过去几乎没有碰过Lua." /p>

This does pass my limited testing ... so I'm really asking about any potential concurrency/atomicity issues and whether there's anything stupid in the Lua --- as I've barely ever touched Lua in the past).

推荐答案

根据 Redis的文档:

Redis使用相同的Lua解释器来运行所有命令.另外,Redis保证以原子方式执行脚本:执行脚本时不会执行其他脚本或Redis命令.这种语义类似于MULTI/EXEC中的一种.从所有其他客户端的角度来看,脚本的效果还是不可见或已经完成.

Redis uses the same Lua interpreter to run all the commands. Also Redis guarantees that a script is executed in an atomic way: no other script or Redis command will be executed while a script is being executed. This semantic is similar to the one of MULTI / EXEC. From the point of view of all the other clients the effects of a script are either still not visible or already completed.

但是,如果脚本太慢,则会导致问题.因此,脚本是需要一些逻辑和原子性的轻型操作的最佳选择.

However, if the script is too slow, it causes problem. So script is the best for light operations that requires some logic and atomicity.

您可能会遇到的另一个漏洞是,如果脚本在中间某种程度上失败了,尽管脚本会返回错误,但您所做的那些调用将无法回滚.

Another loophole you might fall in is, if the script somehow failed in the middle, those calls you've done could not be rolled back, although the script will return error.

例如: 您有一个像这样的脚本:

E.g: You have a script like this:

redis.call('set', 'foo', 1)
redis.call('rpush', 'foo', 2)

脚本执行将返回错误,但是foo已在Redis中设置为1.

The script execution will return error, but foo has already been set in redis as 1.

与您的问题无关的事情:我注意到您曾经使用过

Something unrelated to your question: I noticed that you used

eval "your_raw_code" key_count keys argv

实际上,当您在终端中时,您可以在eval中调用lua脚本文件:

actually you could call the lua script file in eval when you are in the terminal:

> redis-cli eval "$(cat path/to/script/script_name.lua)" key_count keys argv

这篇关于Redis Lua脚本实现CAS(检查并设置)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆