1. 基本用法
1.1 EVAL script numkeys key [key ...] arg [arg ...]
numkeys 是key的個數,後邊接著寫key1 key2... val1 val2....,舉例
127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 val1 val2 1) "key1" 2) "key2" 3) "val1" 4) "val2"
1.2 SCRIPT LOAD script
把指令碼載入到指令碼快取中,返回SHA1校驗和。但不會立馬執行,舉例
127.0.0.1:6379> SCRIPT LOAD "return 'hello world'" "5332031c6b470dc5a0dd9b4bf2030dea6d65de91"
1.3 EVALSHA sha1 numkeys key [key ...] arg [arg ...]
根據快取碼執行指令碼內容。舉例
127.0.0.1:6379> SCRIPT LOAD "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" "a42059b356c875f0717db19a51f6aaca9ae659ea" 127.0.0.1:6379> EVALSHA "a42059b356c875f0717db19a51f6aaca9ae659ea" 2 key1 key2 val1 val2 1) "key1" 2) "key2" 3) "val1" 4) "val2"
1.4 SCRIPT EXISTS script [script ...]
通過sha1校驗和判斷指令碼是否在快取中
1.5 SCRIPT FLUSH
清空快取
127.0.0.1:6379> SCRIPT LOAD "return 'hello jihite'" "3a43944275256411df941bdb76737e71412946fd" 127.0.0.1:6379> SCRIPT EXISTS "3a43944275256411df941bdb76737e71412946fd" 1) (integer) 1 127.0.0.1:6379> SCRIPT FLUSH OK 127.0.0.1:6379> SCRIPT EXISTS "3a43944275256411df941bdb76737e71412946fd" 1) (integer) 0
1.6 SCRIPT KILL
殺死目前正在執行的指令碼
2. 主要優勢
減少網路開銷:多個請求通過指令碼一次傳送,減少網路延遲
原子操作:將指令碼作為一個整體執行,中間不會插入其他命令,無需使用事務
複用:客戶端傳送的指令碼永久存在redis中,其他客戶端可以複用指令碼
可嵌入性:可嵌入JAVA,C#等多種程式語言,支援不同作業系統跨平臺互動
3. 實戰
直接在redis-cli中直接寫lua指令碼,這樣非常不方便編輯,通常情況下我們都是把lua script放到一個lua檔案中,然後執行這個lua指令碼,
示例:活躍使用者判斷:判斷一個遊戲使用者是否屬於活躍使用者,如果符合標準,則活躍使用者人數+1
if redis.call("EXISTS",KEYS[1]) == 1 then return redis.call("INCRBY",KEYS[1],ARGV[1]) else return nil end
儲存位置:
/Users/jihite/activeuser.lua
執行
$ redis-cli --eval /Users/jihite/activeuser.lua user , 1 (integer) 1 127.0.0.1:6379> get user "1" 127.0.0.1:6379> exit $ redis-cli --eval /Users/jihite/activeuser.lua user , 1 (integer) 2 $ redis-cli 127.0.0.1:6379> get user "2" 127.0.0.1:6379> exit $ redis-cli --eval /Users/jihite/activeuser.lua user , 4 (integer) 6
4. 指令碼的安全性
如生成隨機數這一命令,如果在master上執行完後,再在slave上執行會不一樣,這就破壞了主從節點的一致性
為了解決這個問題, Redis 對 Lua 環境所能執行的指令碼做了一個嚴格的限制 —— 所有指令碼都必須是無副作用的純函式(pure function)。所有剛才說的那種情況壓根不存在。Redis 對 Lua 環境做了一些列相應的措施:
- 不提供訪問系統狀態狀態的庫(比如系統時間庫)
- 禁止使用 loadfile 函式
- 如果指令碼在執行帶有隨機性質的命令(比如 RANDOMKEY ),或者帶有副作用的命令(比如 TIME )之後,試圖執行一個寫入命令(比如 SET ),那麼 Redis 將阻止這個指令碼繼續執行,並返回一個錯誤。
- 如果指令碼執行了帶有隨機性質的讀命令(比如 SMEMBERS ),那麼在指令碼的輸出返回給 Redis 之前,會先被執行一個自動的字典序排序,從而確保輸出結果是有序的。
- 用 Redis 自己定義的隨機生成函式,替換 Lua 環境中
math
表原有的 math.random 函式和 math.randomseed 函式,新的函式具有這樣的性質:每次執行 Lua 指令碼時,除非顯式地呼叫math.randomseed
,否則math.random
生成的偽隨機數序列總是相同的。
參考
https://www.runoob.com/redis/redis-scripting.html (基本使用)
https://www.cnblogs.com/Don/articles/5731856.html (例項)
https://www.cnblogs.com/huangxincheng/p/6230129.html
https://redisbook.readthedocs.io/en/latest/feature/scripting.html#lua (安全性)