Redis使用Lua腳本


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  (安全性)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM