Redis事務與Lua
阿新 • • 發佈:2020-11-16
為了保證多條命令組合的原子性, Redis提供了簡單的事務功能以及整合Lua指令碼來解決這個問題。
事務
事務表示一組動作, 要麼全部執行, 要麼全部不執行。
Redis提供了簡單的事務功能, 將一組需要一起執行的命令放到multi和exec兩個命令之間。
multi命令代表事務開始, exec命令代表事務結束,它們之間的命令是原子順序執行的。
如果要停止事務的執行, 可以使用discard命令代替exec命令即可。
如果事務中的命令出現錯誤, Redis的處理機制也不盡相同:
命令錯誤 該種類型屬於語法錯誤, 會造成整個事務無法執行, key和value的值未發生變化。 執行時錯誤 如命令寫錯了,誤把sadd寫為zadd,該種類型會執行成功,且不支援回滾。需要開發人員自己進行修復
有些應用場景需要在事務之前, 確保事務中的key沒有被其他客戶端修改過, 才執行事務, 否則不執行(類似樂觀鎖) 。 Redis提供了watch命令來解決這類問題(multi命令之前執行)。
Redis提供了簡單的事務, 之所以說它簡單, 主要是因為它不支援事務中的回滾特性, 同時無法實現命令之間的邏輯關係計算, 當然也體現了Redis的“keep it simple”的特性。
在Redis中使用Lua
在Redis中執行Lua指令碼有兩種方法: eval和evalsha。
eval
用法:eval 指令碼內容 key個數 key列表 引數列表 示例: > eval 'return "hello " .. KEYS[1] .. ARGV[1]' 1 redis world > "hello redisworld" 此時KEYS[1]="redis", ARGV[1]="world", 所以最終的返回結果是"hello redisworld"。 如果Lua指令碼較長, 還可以使用redis-cli--eval直接執行檔案。
eval命令執行Lua指令碼過程
evalsha
除了使用eval, Redis還提供了evalsha命令來執行Lua指令碼。 首先要將Lua指令碼載入到Redis服務端, 得到該指令碼的SHA1校驗和,evalsha命令使用SHA1作為引數可以直接執行對應Lua指令碼, 避免每次傳送Lua指令碼的開銷。 這樣客戶端就不需要每次執行指令碼內容, 而指令碼也會常駐在服務端, 指令碼功能得到了複用。
用法:
載入指令碼: script load命令可以將指令碼內容載入到Redis記憶體中,得到SHA1。 示例: # redis-cli script load "$(cat lua_get.lua)" "7413dc2440db1fea7c0a0bde841fa68eefaf149c" 執行指令碼: evalsha的使用方法如下, 引數使用SHA1值, 執行邏輯和eval一致。 用法:evalsha 指令碼SHA1值 key個數 key列表 引數列表 示例: # evalsha 7413dc2440db1fea7c0a0bde841fa68eefaf149c 1 redis world "hello redisworld"
使用evalsha執行Lua指令碼過程
Lua指令碼功能為Redis開發和運維人員帶來如下三個好處:
·Lua指令碼在Redis中是原子執行的, 執行過程中間不會插入其他命令。
·Lua指令碼可以幫助開發和運維人員創造出自己定製的命令, 並可以將這些命令常駐在Redis記憶體中, 實現複用的效果。
·Lua指令碼可以將多條命令一次性打包, 有效地減少網路開銷。
Redis管理Lua指令碼相關命令
script load script 此命令用於將Lua指令碼載入到Redis記憶體中。 script exists 判斷sha1是否已經載入到Redis記憶體中。 script flush 清除Redis記憶體已經載入的所有Lua指令碼。 script kill 殺掉正在執行的Lua指令碼。如果Lua指令碼比較耗時, 甚至Lua指令碼存在問題, 那麼此時Lua指令碼的執行會阻塞Redis, 直到指令碼執行完畢或者外部進行干預將其結束。 (如果當前Lua指令碼正在執行寫操作, 那麼script kill將不會生效)
Redis Lua相關引數
lua-time-limit 預設5s,當Lua指令碼時間超過lua-time-limit後, 向其他命令呼叫傳送BUSY的訊號, 但是並不會停止掉服務端和客戶端的指令碼執行,
所以當達到lua-time-limit值之後, 其他客戶端在執行正常的命令時, 將會收到“Busy Redis is busy running a script”錯誤, 並且提示使用script kill或者shutdown nosave命令來殺掉這個busy的指令碼