失蹤人口回來啦!
有讀者問我為什么這么久都沒有出Redis Lua中學教程,表示村頭廁所已經好久沒有紙了。其實我早就要寫這篇中學教程了,奈何最近太忙了,就一拖再拖,直到今天我終于又開始動筆了。忘記Lua相關概念的同學可以先回顧一下小學教程。
lua編寫游戲腳本教程。中學教程主要分為兩部分:Redis Lua的相關命令詳解和Lua的語法介紹。
前面我們簡單介紹了EVAL和EVALSHA命令。但是只有那點只是是沒辦法從中學畢業的,因此我們需要進行更深入的學習。
最早可用版本:2.6.0
用法:EVAL script numkeys key [key ...] arg [arg ...]
lua腳本怎么寫?關于用法我們已經演示過了,其中第一個參數是要執行的Lua腳本,第二個參數是傳入腳本的參數個數。后面則是參數的key數組和value數組。
在Lua中執行Redis命令的方法我們也介紹過,就是使用redis.call()和redis.pcall()兩個函數。它們之間唯一的不同就是當Redis命令執行錯誤時,redis.call()會拋出這個錯誤,使EVAL命令拋出錯誤,而redis.pcall()會捕獲這個錯誤,并返回Lua的錯誤表。
通常我們約定執行命令的key都需要由參數傳入,命令必須在執行之前進行分析,以確定它作用于哪個key。這樣做的目的是為了在一定程度上保證EVAL執行的Lua腳本的正確性。
在Redis執行EVAL命令時,如果腳本中有call()或者pcall()命令,就會涉及到Redis和Lua之間數據類型轉換的問題。轉換規則要求,一個Redis的返回值轉換成Lua數據類型后,再轉換成Redis數據類型,其結果必須和初始值相同。所以每種類型是一一對應的。轉換規則如下:
andlua輔助源碼?
除此之外,Lua到Redis的轉換還有一些其他的規則:
來個栗子驗證一下:
EVAL "return {1,2,3.3333,'foo',nil,'bar'}" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"
可以看到bar沒有返回,并且3.333返回了3。
lua編程指南。Redis運行所有的Lua命令都使用相同的Lua解釋器。當一個腳本正在執行時,其他的腳本或Redis命令都不能執行。這很像Redis的事務multi/exec。這意味著我們要盡量避免腳本的執行時間過長。
當腳本進行傳播或者寫入AOF文件時,Redis通常會將腳本本身進行傳播或寫入AOF,而不是使用它產生的若干命令。原因很簡單,傳播整個腳本要比傳播一大堆生成的命令的速度要快。
從Redis3.2開始,可以只復制影響腳本執行結果的語句,而不用復制整個腳本。這個復制整個腳本的方法有以下屬性:
在這種模式下,Redis在執行腳本時會收集所有影響數據集的命令,當腳本執行完畢時,命令隊列會被放在事務中,發送給AOF文件。
python lua,Lua可以通過執行redis.replicate_commands()函數來檢查復制模式,如果返回true表示當前是復制命令模式,如果返回false,則是復制整個腳本模式。
腳本復制模式選擇好以后,就可以對復制到副本和AOF的方式進行更多的控制。這是一種高級特性,因為濫用會切斷主從備份,和AOF持久化。如果我們只需要在master上執行某些命令時,這一特性就變得很有用。例如我們需要計算一些中間值時,只需要在master上計算就好,那么這些命令就不必進行復制。
從Redis3.2開始,有一個新的命令叫做redis.set_repl(),它可以用來控制復制方式,有如下選項(默認是REPL_ALL):
redis.set_repl(redis.REPL_ALL) -- Replicate to AOF and replicas.
redis.set_repl(redis.REPL_AOF) -- Replicate only to AOF.
redis.set_repl(redis.REPL_REPLICA) -- Replicate only to replicas (Redis >= 5)
redis.set_repl(redis.REPL_SLAVE) -- Used for backward compatibility, the same as REPL_REPLICA.
redis.set_repl(redis.REPL_NONE) -- Don't replicate at all.
為了避免數據泄露,Redis腳本不允許創建全局變量。如果必須有一個公共變量,可以使用Redis的key來代替。在EVAL命令中創建一個全局變量會引起一個異常。
> eval 'a=10' 0
(error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a
lua游戲源碼?在Lua腳本中使用SELECT就像在正常客戶端中使用一樣。值得一提的是,在Redis2.8.12之前,Lua腳本中執行SELECT是會影響到客戶端的,而從2.8.12開始,Lua腳本中的SELECT只會在腳本執行過程中生效。這點在Redis版本升級時需要注意,因為升級前后,命令的語義會改變。
Lua腳本中有許多庫,但并不是都能在Redis中使用,其中可以使用的有:
base
lib.table
lib.string
lib.math
lib.struct
lib.cjson
lib.cmsgpack
lib.bitop
lib.redis.sha1hex
function.redis.breakpoint and redis.debug
function in the context of the Redis Lua debugger.struct, CJSON and cmsgpack是外部庫,其他的都是Lua的標準庫。
使用redis.log(loglevel,message)函數可以在Lua腳本中打印Redis日志。
Lua腳本?loglevel包括:
它們與Redis的日志等級是對應的。
腳本不應該訪問外部系統,包括文件系統和其他系統。腳本應該只能操作Redis數據和傳入進來的參數。
腳本默認的最大執行時間是5秒(正常腳本執行時間都是毫秒級,所以5秒已經足夠長了)。可以通過修改lua-time-limit變量來控制最大執行時間。
源碼怎么用?當腳本執行時間超過最大執行時間時,并不會被自動終止,因為這違反了腳本的原子性原則。當一個腳本執行時間過長時,Redis會有如下操作:
最早可用版本:2.6.0
用法:EVALSHA sha1 numkeys key [key ...] arg [arg ...]
該命令用來執行緩存在服務器上的腳本,sha1為腳本的唯一標識。
lua,使用EVAL命令必須每次都要把腳本從客戶端傳到服務器,由于Redis的內部緩存機制,它并不會每次都重新編譯腳本,但是傳輸上仍然浪費帶寬。
另一方面,如果使用特殊命令或者通過redis.conf來定義命令會有以下問題:
為了避免這些問題,同時避免浪費帶寬,Redis實現了EVALSHA命令。
如果服務器中沒有緩存指定的腳本,會返回給客戶端腳本不存在的錯誤信息。
lua游戲腳本教程,最早可用版本:3.2.0
時間復雜度:O(1)
用法:SCRIPT DEBUG YES|SYNC|NO
該命令用于設置隨后執行的EVAL命令的調試模式。Redis包含一個完整的Lua調試器,代號為LDB,可以使編寫復雜腳本的任務更加簡單,在調試模式下,Redis充當遠程調試服務器,客戶端可以逐步執行腳本,設置斷點,檢查變量等。想了解更多調試器內容的可以查看官方文檔Redis Lua debugger。
lua腳本編寫教程詳細?LDB可以設置成異步或同步模式。異步模式下,服務器會fork出一個調試會話,不會阻塞主會話,,調試會話結束后,所有數據都會回滾。同步模式則會阻塞會話,并保留調試過程中數據的改變。
最早可用版本:2.6.0
時間復雜度:O(N),N是腳本數量
返回腳本是否存在于緩存中(存在返回1,不存在返回0)。這個命令適合在管道前執行,以保證管道中的所有腳本都已經加載到服務器端了,如果沒有,需要用SCRIPT LOAD命令進行加載。
lua中文手冊、最早可用版本:2.6.0
時間復雜度:O(N),N是緩存中的腳本數
刷新緩存中的腳本,這一命令常在云服務上被使用。
最早可用版本:2.6.0
時間復雜度:O(1)
停止當前正在執行的Lua腳本,通常用來停止執行時間過長的腳本。停止后,被阻塞的客戶端會拋出一個錯誤。
最早可用版本:2.6.0
時間復雜度:O(N),N是腳本的字節數
該命令用于將腳本加載到服務器端的緩存中,但不會執行。加載后,服務器會一直緩存,因為良好的應用程序不太可能有太多不同的腳本導致內存不足。每個腳本都像一個新命令的緩存,所以即使是大型應用程序,也就有幾百個,它們占用的內存是微不足道的。
本文介紹了Redis Lua相關的命令。其中EVAL和EVALSHA用來執行腳本。腳本執行具有原子性。腳本的復制和傳播可以根據需要設置。腳本中不能定義全局變量。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态