天天看點

Redis下Lua腳本的複制模式

假設我們的Redis選擇了主從架構, 和AOF持久化方式.

當我們執行一條寫指令時, 該條指令會被發送到從伺服器, 和追加到AOF檔案中.

當我們執行的不是一條指令, 而是Lua腳本時, 預設情況下, 整個Lua腳本的内容會進行複制, 但是存在一些特殊情況, 我們來看一個例子, Lua腳本内容如下:

-- 目前時間
local now_time = redis.call('TIME');
-- 設定OPERATE_TIME值為目前秒數
redis.call('SET','OPERATE_TIME',now_time[1]);           

預設執行的時候, 會報錯如下:

Write commands not allowed after non deterministic commands. Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.            

翻譯過來就是說, 寫指令不被允許出現在‘非确定性指令’的後面, 請在腳本開始時調用

redis.replicate_commands()

來切換到指令複制模式.

修改之後的Lua腳本内容如下:

-- 開啟單指令複制模式
redis.replicate_commands();
-- 目前時間
local now_time = redis.call('TIME');
-- 設定OPERATE_TIME值為目前秒數
redis.call('SET','OPERATE_TIME',now_time[1]);           

再執行就不會報錯, 然後我們到AOF檔案下去檢視一下, 我們發現追加的不是腳本内容, 而是

MULTI...EXEC

指令:

$1
0
*1
$5
MULTI
*3
$3
SET
$12
OPERATE_TIME
$10
1572855544
*1
$4
EXEC           

回到腳本上來, 我們的腳本包含了

TIME

指令來擷取系統時間, 這個指令在不同時間去執行傳回的值肯定不一樣, 如果在主從複制和AOF追加時, 直接複制整個腳本的内容, 那麼肯定會造成執行時資料的不一緻性.

是以, 在執行Lua時Redis預設不允許動态的不确定性的變量存在. 如果存在, 則需要開啟指令複制模式, 即隻複制Lua腳本裡包含的寫指令, 所有的寫指令會被包裝在

MULTI ... EXEC

裡.

Redis官方, 把預設的複制整個腳本内容的模式定義為

whole scripts replication

, 把隻複制腳本裡寫指令的模式定義為

script effects replication

.

在指令複制模式下, 還可以選擇是否對某個指令進行目标複制, 即是否需要複制到‘從伺服器’和‘AOF檔案’ , 如下:

redis.set_repl(redis.REPL_ALL) -- Replicate to AOF and slaves.
redis.set_repl(redis.REPL_AOF) -- Replicate only to AOF.
redis.set_repl(redis.REPL_SLAVE) -- Replicate only to slaves.
redis.set_repl(redis.REPL_NONE) -- Don't replicate at all.           

舉個例子:

redis.replicate_commands() -- 開啟指令複制模式
redis.call('set','A','1')
redis.set_repl(redis.REPL_NONE) -- 不進行複制
redis.call('set','B','2')
redis.set_repl(redis.REPL_ALL) -- 複制到所有,即從伺服器和AOF檔案
redis.call('set','C','3')           

在執行完腳本之後, 隻有A和C的寫操作會進行複制. 這種選擇性複制的功能, 在需要過濾掉一些沒必要的臨時變量時有點用途, 但是提升不了太多性能, 而且操作有風險, 是以可以忽略掉此功能.

當然, 在執行Lua時, 并不是隻有出現像TIME這樣的非确定性指令時才可以開啟指令複制模式, 如果你的腳本内容太多, 而寫操作就隻有幾條, 那麼為了提高效率也可以選擇開啟.

繼續閱讀