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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章