Redis Lua脚本原子性的注意点

先看一下Redis官方对Lua脚本的解释:https://redis.io/commands/eval

“Atomicity of scripts

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.”

大致翻译:

“脚本原子性

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

注意事项:

       需要注意的是redis.call()函数出错时会中断脚本的执行,此时会出现一部分命令执行了,一部分没有执行。测试如下:

采用的redis版本为:5.0.7

准备数据:

127.0.0.1:6379> set haha haha
OK
127.0.0.1:6379> set key1 1
OK
127.0.0.1:6379> set key2 2
OK

执行一段中间调用redis.call()会出错的Lua脚本,错误原因haha的key类型是字符串,执行HGET命令会出错的:

127.0.0.1:6379> eval "redis.call('SET',KEYS[1],ARGV[1]);redis.call('HGET','haha',ARGV[1]);redis.call('SET',KEYS[2],ARGV[2]);return 1;" 2 key1 key2 11 22
(error) ERR Error running script (call to f_cf874476bb7116d92b3b0cbbf8b399ba853907d4): @user_script:1: WRONGTYPE Operation against a key holding the wrong kind of value 
127.0.0.1:6379> get key1
"11"
127.0.0.1:6379> get key2
"2"
127.0.0.1:6379> get haha
"haha"
127.0.0.1:6379> 

可以看到key1被设置成了11,但是key2没有变成22,因为中间一步redis.call('HGET','haha',ARGV[1]);出错中断了脚本的执行。

redis.pcall()函数不会中断Lua脚本的执行,比如接着上面执行脚本:

127.0.0.1:6379> eval "redis.pcall('SET',KEYS[1],ARGV[1]);redis.pcall('HGET','haha',ARGV[1]);redis.pcall('SET',KEYS[2],ARGV[2]);return 1;" 2 key1 key2 1 22
(integer) 1
127.0.0.1:6379> get haha
"haha"
127.0.0.1:6379> get key1
"1"
127.0.0.1:6379> get key2
"22"
127.0.0.1:6379> 

所以为了保证脚本的原子性,要谨慎使用redis.call()函数,如使用一定要确保这个函数的正确性。

发布了41 篇原创文章 · 获赞 105 · 访问量 14万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章