redis命令詳解與使用情境舉例——Script(指令碼)

來源:互聯網
上載者:User
EVAL script numkeys key [key …] arg [arg …]

從 Redis 2.6.0 版本開始,通過內建的 Lua 解譯器,可以使用 EVAL 命令對 Lua 指令碼進行求值。
script 參數是一段 Lua 5.1 指令碼程式,它會被運行在 Redis 伺服器上下文中,這段指令碼不必(也不應該)定義為一個 Lua 函數。
numkeys 參數用於指定鍵名參數的個數。
鍵名參數 key [key …] 從 EVAL 的第三個參數開始算起,表示在指令碼中所用到的那些 Redis 鍵(key),這些鍵名參數可以在 Lua 中通過全域變數 KEYS 數組,用 1 為基址的形式訪問( KEYS[1] , KEYS[2] ,以此類推)。
在命令的最後,那些不是鍵名參數的附加參數 arg [arg …] ,可以在 Lua 中通過全域變數 ARGV 數組訪問,訪問的形式和 KEYS 變數類似( ARGV[1] 、 ARGV[2] ,諸如此類)。
上面這幾段長長的說明可以用一個簡單的例子來概括:

> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second1) "key1"2) "key2"3) "first"4) "second"

其中 “return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}” 是被求值的 Lua 指令碼,數字 2 指定了鍵名參數的數量, key1 和 key2 是鍵名參數,分別使用 KEYS[1] 和 KEYS[2] 訪問,而最後的 first 和 second 則是附加參數,可以通過 ARGV[1] 和 ARGV[2] 訪問它們。
在 Lua 指令碼中,可以使用兩個不同函數來執行 Redis 命令,它們分別是:
● redis.call()
● redis.pcall()
這兩個函數的唯一區別在於它們使用不同的方式處理執行命令所產生的錯誤,在後面的『錯誤處理』部分會講到這一點。
redis.call() 和 redis.pcall() 兩個函數的參數可以是任何格式良好(well formed)的 Redis 命令:

> eval "return redis.call('set','foo','bar')" 0OK

需要注意的是,上面這段指令碼的確實現了將鍵 foo 的值設為 bar 的目的,但是,它違反了 EVAL 命令的語義,因為指令碼裡使用的所有鍵都應該由 KEYS 數組來傳遞,就像這樣:

> eval "return redis.call('set',KEYS[1],'bar')" 1 fooOK

要求使用正確的形式來傳遞鍵(key)是有原因的,因為不僅僅是 EVAL 這個命令,所有的 Redis 命令,在執行之前都會被分析,籍此來確定命令會對哪些鍵進行操作。
因此,對於 EVAL 命令來說,必須使用正確的形式來傳遞鍵,才能確保分析工作正確地執行。除此之外,使用正確的形式來傳遞鍵還有很多其他好處,它的一個特別重要的用途就是確保 Redis 叢集可以將你的請求發送到正確的叢集節點。(對 Redis 叢集的工作還在進行當中,但是指令碼功能被設計成可以與叢集功能保持相容。)不過,這條規矩並不是強制性的,從而使得使用者有機會濫用(abuse) Redis 單一實例配置(single instance configuration),代價是這樣寫出的指令碼不能被 Redis 叢集所相容。
在 Lua 資料類型和 Redis 資料類型之間轉換
當 Lua 通過 call() 或 pcall() 函數執行 Redis 命令的時候,命令的傳回值會被轉換成 Lua 資料結構。同樣地,當 Lua 指令碼在 Redis 內建的解譯器裡運行時,Lua 指令碼的傳回值也會被轉換成 Redis 協議(protocol),然後由 EVAL 將值返回給用戶端。
資料類型之間的轉換遵循這樣一個設計原則:如果將一個 Redis 值轉換成 Lua 值,之後再將轉換所得的 Lua 值轉換回 Redis 值,那麼這個轉換所得的 Redis 值應該和最初時的 Redis 值一樣。
換句話說, Lua 類型和 Redis 類型之間存在著一一對應的轉換關係。
以下列出的是詳細的轉換規則:
從 Redis 轉換到 Lua :
● Redis integer reply -> Lua number / Redis 整數轉換成 Lua 數字
● Redis bulk reply -> Lua string / Redis bulk 回複轉換成 Lua 字串
● Redis multi bulk reply -> Lua table (may have other Redis data types nested) / Redis 多條 bulk 回複轉換成 Lua 表,表內可能有其他別的 Redis 資料類型
● Redis status reply -> Lua table with a single ok field containing the status / Redis 狀態回複轉換成 Lua 表,表內的 ok 域包含了狀態資訊
● Redis error reply -> Lua table with a single err field containing the error / Redis 錯誤回複轉換成 Lua 表,表內的 err 域包含了錯誤資訊
● Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type / Redis 的 Nil 回複和 Nil 多條回複轉換成 Lua 的布爾值 false
從 Lua 轉換到 Redis:
● Lua number -> Redis integer reply / Lua 數字轉換成 Redis 整數
● Lua string -> Redis bulk reply / Lua 字串轉換成 Redis bulk 回複
● Lua table (array) -> Redis multi bulk reply / Lua 表(數組)轉換成 Redis 多條 bulk 回複
● Lua table with a single ok field -> Redis status reply / 一個帶單個 ok 域的 Lua 表,轉換成 Redis 狀態回複
● Lua table with a single err field -> Redis error reply / 一個帶單個 err 域的 Lua 表,轉換成 Redis 錯誤回複
● Lua boolean false -> Redis Nil bulk reply / Lua 的布爾值 false 轉換成 Redis 的 Nil bulk 回複
從 Lua 轉換到 Redis 有一條額外的規則,這條規則沒有和它對應的從 Redis 轉換到 Lua 的規則:
● Lua boolean true -> Redis integer reply with value of 1 / Lua 布爾值 true 轉換成 Redis 整數回複中的 1
以下是幾個類型轉換的例子:

> eval "return 10" 0(integer) 10> eval "return {1,2,{3,'Hello World!'}}" 01) (integer) 12) (integer) 23) 1) (integer) 3   2) "Hello World!"> eval "return redis.call('get','foo')" 0"bar"

在上面的三個程式碼範例裡,前兩個示範了如何將 Lua 值轉換成 Redis 值,最後一個例子更複雜一些,它示範了一個將 Redis 值轉換成 Lua 值,然後再將 Lua 值轉換成 Redis 值的類型轉過程。
指令碼的原子性
Redis 使用單個 Lua 解譯器去運行所有指令碼,並且, Redis 也保證指令碼會以原子性(atomic)的方式執行:當某個指令碼正在啟動並執行時候,不會有其他指令碼或 Redis 命令被執行。這和使用 MULTI / EXEC 包圍的事務很類似。在其他別的用戶端看來,指令碼的效果(effect)要麼是不可見的(not visible),要麼就是已完成的(already completed)。
另一方面,這也意味著,執行一個運行緩慢的指令碼並不是一個好主意。寫一個跑得很快很順溜的指令碼並不難,因為指令碼的運行開銷(overhead)非常少,但是當你不得不使用一些跑得比較慢的指令碼時,請小心,因為當這些蝸牛指令碼在慢吞吞地啟動並執行時候,其他用戶端會因為伺服器正忙而無法執行命令。
錯誤處理
前面的命令介紹部分說過, redis.call() 和 redis.pcall() 的唯一區別在於它們對錯誤處理的不同。
當 redis.call() 在執行命令的過程中發生錯誤時,指令碼會停止執行,並返回一個指令碼錯誤,錯誤的輸出資訊會說明錯誤造成的原因:

redis> lpush foo a(integer) 1redis> eval "return redis.call('get', 'foo')" 0(error) ERR Error running script (call to f_282297a0228f48cd3fc6a55de6316f31422f5d17): ERR Operation against a key holding the wrong kind of value

和 redis.call() 不同, redis.pcall() 出錯時並不引發(raise)錯誤,而是返回一個帶 err 域的 Lua 表(table),用於表示錯誤:

redis 127.0.0.1:6379> EVAL "return redis.pcall('get', 'foo')" 0(error) ERR Operation against a key holding the wrong kind of value

頻寬和 EVALSHA
EVAL 命令要求你在每次執行指令碼的時候都發送一次指令碼主體(script body)。Redis 有一個內部的緩衝機制,因此它不會每次都重新編譯指令碼,不過在很多場合,付出無謂的頻寬來傳送指令碼主體並不是最佳選擇。
為了減少頻寬的消耗, Redis 實現了 EVALSHA 命令,它的作用和 EVAL 一樣,都用於對指令碼求值,但它接受的第一個參數不是指令碼,而是指令碼的 SHA1 校正和(sum)。
EVALSHA 命令的表現如下:
● 如果伺服器還記得給定的 SHA1 校正和所指定的指令碼,那麼執行這個指令碼
● 如果伺服器不記得給定的 SHA1 校正和所指定的指令碼,那麼它返回一個特殊的錯誤,提醒使用者使用 EVAL 代替 EVALSHA
以下是樣本:

> set foo barOK> eval "return redis.call('get','foo')" 0"bar"> evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0"bar"> evalsha ffffffffffffffffffffffffffffffffffffffff 0(error) `NOSCRIPT` No matching script. Please use [EVAL](/commands/eval).

用戶端庫的底層實現可以一直樂觀地使用 EVALSHA 來代替 EVAL ,並期望著要使用的指令碼已經儲存在伺服器上了,只有當 NOSCRIPT 錯誤發生時,才使用 EVAL 命令重新發送指令碼,這樣就可以最大限度地節省頻寬。
這也說明了執行 EVAL 命令時,使用正確的格式來傳遞鍵名參數和附加參數的重要性:因為如果將參數硬寫在指令碼中,那麼每次當參數改變的時候,都要重新發送指令碼,即使指令碼的主體並沒有改變,相反,通過使用正確的格式來傳遞鍵名參數和附加參數,就可以在指令碼主體不變的情況下,直接使用 EVALSHA 命令對指令碼進行複用,免去了無謂的頻寬消耗。
指令碼緩衝
Redis 保證所有被運行過的指令碼都會被永久儲存在指令碼緩衝當中,這意味著,當 EVAL 命令在一個 Redis 執行個體上成功執行某個指令碼之後,隨後針對這個指令碼的所有 EVALSHA 命令都會成功執行。
重新整理指令碼緩衝的唯一辦法是顯式地調用 SCRIPT FLUSH 命令,這個命令會清空運行過的所有指令碼的緩衝。通常只有在雲端運算環境中,Redis 執行個體被改作其他客戶或者別的應用程式的執行個體時,才會執行這個命令。
緩衝可以長時間儲存而不產生記憶體問題的原因是,它們的體積非常小,而且數量也非常少,即使指令碼在概念上類似於實現一個新命令,即使在一個大規模的程式裡有成百上千的指令碼,即使這些指令碼會經常修改,即便如此,儲存這些指令碼的記憶體仍然是微不足道的。
事實上,使用者會發現 Redis 不移除緩衝中的指令碼實際上是一個好主意。比如說,對於一個和 Redis 保持持久化連結(persistent connection)的程式來說,它可以確信,執行過一次的指令碼會一直保留在記憶體當中,因此它可以在流水線中使用 EVALSHA 命令而不必擔心因為找不到所需的指令碼而產生錯誤(稍候我們會看到在流水線中執行指令碼的相關問題)。
SCRIPT 命令
Redis 提供了以下幾個 SCRIPT 命令,用於對指令碼子系統(scripting subsystem)進行控制:
● SCRIPT FLUSH :清除所有指令碼緩衝
● SCRIPT EXISTS :根據給定的指令碼校正和,檢查指定的指令碼是否存在於指令碼緩衝
● SCRIPT LOAD :將一個指令碼裝入指令碼緩衝,但並不立即運行它
● SCRIPT KILL :殺死當前正在啟動並執行指令碼
純函數指令碼
在編寫指令碼方面,一個重要的要求就是,指令碼應該被寫成純函數(pure function)。
也就是說,指令碼應該具有以下屬性:
● 對於同樣的資料集輸入,給定相同的參數,指令碼執行的 Redis 寫命令總是相同的。指令碼執行的操作不能依賴於任何隱藏(非顯式)資料,不能依賴於指令碼在執行過程中、或指令碼在不同執行時期之間可能變更的狀態,並且它也不能依賴於任何來自 I/O 裝置的外部輸入。
使用系統時間(system time),調用像 RANDOMKEY 那樣的隨機命令,或者使用 Lua 的隨機數產生器,類似以上的這些操作,都會造成指令碼的求值無法每次都得出同樣的結果。
為了確保指令碼符合上面所說的屬性, Redis 做了以下工作:
● Lua 沒有訪問系統時間或者其他內部狀態的命令
● Redis 會返回一個錯誤,阻止這樣的指令碼運行: 這些指令碼在執行隨機命令之後(比如 RANDOMKEY 、 SRANDMEMBER 或 TIME 等),還會執行可以修改資料集的 Redis 命令。如果指令碼只是執行唯讀操作,那麼就沒有這一限制。注意,隨機命令並不一定就指那些帶 RAND 字眼的命令,任何帶有非確定性命令都會被認為是隨機命令,比如 TIME 命令就是這方面的一個很好的例子。
● 每當從 Lua 指令碼中調用那些返回無序元素的命令時,執行命令所得的資料在返回給 Lua 之前會先執行一個靜默(slient)的字典序排序(lexicographical sorting)。舉個例子,因為 Redis 的 Set 儲存的是無序的元素,所以在 Redis 命令列用戶端中直接執行 SMEMBERS ,返回的元素是無序的,但是,假如在指令碼中執行 redis.call(“smembers”, KEYS[1]) ,那麼返回的總是排過序的元素。
● 對 Lua 的偽隨機數產生函數 math.random 和 math.randomseed 進行修改,使得每次在運行新指令碼的時候,總是擁有同樣的 seed 值。這意味著,每次運行指令碼時,只要不使用 math.randomseed ,那麼 math.random 產生的隨機數序列總是相同的。
儘管有那麼多的限制,但使用者還是可以用一個簡單的技巧寫出帶隨機行為的指令碼(如果他們需要的話)。
假設現在我們要編寫一個 Redis 指令碼,這個指令碼從列表中彈出 N 個隨機數。一個 Ruby 寫的例子如下:

require 'rubygems'require 'redis'r = Redis.newRandomPushScript = <<EOF    local i = tonumber(ARGV[1])    local res    while (i > 0) do        res = redis.call('lpush',KEYS[1],math.random())        i = i-1    end    return resEOFr.del(:mylist)puts r.eval(RandomPushScript,[:mylist],[10,rand(2**32)])

這個程式每次運行都會產生帶有以下元素的列表:

> lrange mylist 0 -11) "0.74509509873814"2) "0.87390407681181"3) "0.36876626981831"4) "0.6921941534114"5) "0.7857992587545"6) "0.57730350670279"7) "0.87046522734243"8) "0.09637165539729"9) "0.74990198051087"10) "0.17082803611217"

上面的 Ruby 程式每次都只產生同樣的列表,用途並不是太大。那麼,該怎樣修改這個指令碼,使得它仍然是一個純函數(符合 Redis 的要求),但是每次調用都可以產生不同的隨機元素呢。
一個簡單的辦法是,為指令碼添加一個額外的參數,讓這個參數作為 Lua 的隨機數產生器的 seed 值,這樣的話,只要給指令碼傳入不同的 seed ,指令碼就會產生不同的列表元素。
以下是修改後的指令碼:

RandomPushScript = <<EOF    local i = tonumber(ARGV[1])    local res    math.randomseed(tonumber(ARGV[2]))    while (i > 0) do        res = redis.call('lpush',KEYS[1],math.random())        i = i-1    end    return resEOFr.del(:mylist)puts r.eval(RandomPushScript,1,:mylist,10,rand(2**32))

儘管對於同樣的 seed ,上面的指令碼產生的列表元素是一樣的(因為它是一個純函數),但是只要每次在執行指令碼的時候傳入不同的 seed ,我們就可以得到帶有不同隨機元素的列表。
Seed 會在複製(replication link)和寫 AOF 檔案時作為一個參數來傳播,保證在載入 AOF 檔案或附屬節點(slave)處理指令碼時, seed 仍然可以及時得到更新。
注意,Redis 實現保證 math.random 和 math.randomseed 的輸出和運行 Redis 的系統架構無關,無論是 32 位還是 64 位元系統,無論是小端(little endian)還是大端(big endian)系統,這兩個函數的輸出總是相同的。
全域變數保護
為了防止不必要的資料泄漏進 Lua 環境, Redis 指令碼不允許建立全域變數。如果一個指令碼需要在多次執行之間維持某種狀態,它應該使用 Redis key 來進行狀態儲存。
企圖在指令碼中訪問一個全域變數(不論這個變數是否存在)將引起指令碼停止, EVAL 命令會返回一個錯誤:

redis 127.0.0.1:6379> eval 'a=10' 0(error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a'

Lua 的 debug 工具,或者其他設施,比如列印(alter)用於實現全域保護的 meta table ,都可以用於實現全域變數保護。
實現全域變數保護並不難,不過有時候還是會不小心而為之。一旦使用者在指令碼中混入了 Lua 全域狀態,那麼 AOF 持久化和複製(replication)都會無法保證,所以,請不要使用全域變數。
避免引入全域變數的一個訣竅是:將指令碼中用到的所有變數都使用 local 關鍵字定義為局部變數。

Redis 內建的 Lua 解譯器載入了以下 Lua 庫:
● base
● table
● string
● math
● debug
● cjson
● cmsgpack
其中 cjson 庫可以讓 Lua 以非常快的速度處理 JSON 資料,除此之外,其他別的都是 Lua 的標準庫。
每個 Redis 執行個體都保證會載入上面列舉的庫,從而確保每個 Redis 指令碼的運行環境都是相同的。
使用指令碼散發 Redis 日誌
在 Lua 指令碼中,可以通過調用 redis.log 函數來寫 Redis 日誌(log):
redis.log(loglevel, message)
其中, message 參數是一個字串,而 loglevel 參數可以是以下任意一個值:
● redis.LOG_DEBUG
● redis.LOG_VERBOSE
● redis.LOG_NOTICE
● redis.LOG_WARNING
上面的這些等級(level)和標準 Redis 日誌的等級相對應。
對於指令碼散發(emit)的日誌,只有那些和當前 Redis 執行個體所設定的日誌等級相同或更進階的日誌才會被散發。
以下是一個日誌樣本:

redis.log(redis.LOG_WARNING, "Something is wrong with this script.")

執行上面的函數會產生這樣的資訊:
[32343] 22 Mar 15:21:39 # Something is wrong with this script.
沙箱(sandbox)和最大執行時間
指令碼應該僅僅用於傳遞參數和對 Redis 資料進行處理,它不應該嘗試去訪問外部系統(比如檔案系統),或者執行任何系統調用。
除此之外,指令碼還有一個最大執行時間限制,它的預設值是 5 秒鐘,一般正常運作的指令碼通常可以在幾分之幾毫秒之內完成,花不了那麼多時間,這個限制主要是為了防止因編程錯誤而造成的無限迴圈而設定的。
最大執行時間的長短由 lua-time-limit 選項來控制(以毫秒為單位),可以通過編輯 redis.conf 檔案或者使用 CONFIG GET 和 CONFIG SET 命令來修改它。
當一個指令碼達到最大執行時間的時候,它並不會自動被 Redis 結束,因為 Redis 必須保證指令碼執行的原子性,而中途停止指令碼的運行意味著可能會留下未處理完的資料在資料集(data set)裡面。
因此,當指令碼啟動並執行時間超過最大執行時間後,以下動作會被執行:
● Redis 記錄一個指令碼正在逾時運行
● Redis 開始重新接受其他用戶端的命令請求,但是只有 SCRIPT KILL 和 SHUTDOWN NOSAVE 兩個命令會被處理,對於其他命令請求, Redis 伺服器只是簡單地返回 BUSY 錯誤。
● 可以使用 SCRIPT KILL 命令將一個僅執行唯讀命令的指令碼殺死,因為唯讀命令並不修改資料,因此殺死這個指令碼並不破壞資料的完整性
● 如果指令碼已經執行過寫命令,那麼唯一允許執行的操作就是 SHUTDOWN NOSAVE ,它通過停止伺服器來阻止當前資料集寫入磁碟
流水線(pipeline)上下文(context)中的 EVALSHA
在流水線請求的上下文中使用 EVALSHA 命令時,要特別小心,因為在流水線中,必須保證命令的執行順序。
一旦在流水線中因為 EVALSHA 命令而發生 NOSCRIPT 錯誤,那麼這個流水線就再也沒有辦法重新執行了,否則的話,命令的執行順序就會被打亂。
為了防止出現以上所說的問題,用戶端庫實現應該實施以下的其中一項措施:
● 總是在流水線中使用 EVAL 命令
● 檢查流水線中要用到的所有命令,找到其中的 EVAL 命令,並使用 SCRIPT EXISTS 命令檢查要用到的指令碼是不是全都已經儲存在緩衝裡面了。如果所需的全部指令碼都可以在緩衝裡找到,那麼就可以放心地將所有 EVAL 命令改成 EVALSHA 命令,否則的話,就要在流水線的頂端(top)將缺少的指令碼用 SCRIPT LOAD 命令加上去。
可用版本:
2.6.0+
時間複雜度:
EVAL 和 EVALSHA 可以在 O(1) 複雜度內找到要被執行的指令碼,其餘的複雜度取決於執行的指令碼本身。 EVALSHA sha1 numkeys key [key …] arg [arg …]

根據給定的 sha1 校正碼,對緩衝在伺服器中的指令碼進行求值。
將指令碼緩衝到伺服器的操作可以通過 SCRIPT LOAD 命令進行。
這個命令的其他地方,比如參數的傳入方式,都和 EVAL 命令一樣。
可用版本:
2.6.0+
時間複雜度:
根據指令碼的複雜度而定。

redis> SCRIPT LOAD "return 'hello moto'""232fd51614574cf0867b83d384a5e898cfd24e5a"redis> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0"hello moto"
SCRIPT EXISTS script [script …]

給定一個或多個指令碼的 SHA1 校正和,返回一個包含 0 和 1 的列表,表示校正和所指定的指令碼是否已經被儲存在緩衝當中。
關於使用 Redis 對 Lua 指令碼進行求值的更多資訊,請參見 EVAL 命令。
可用版本:
2.6.0+
時間複雜度:
O(N) , N 為給定的 SHA1 校正和的數量。
傳回值:
一個列表,包含 0 和 1 ,前者表示指令碼不存在於緩衝,後者表示指令碼已經在緩衝裡面了。
列表中的元素和給定的 SHA1 校正和保持對應關係,比如列表的第三個元素的值就表示第三個 SHA1 校正和所指定的指令碼在緩衝中的狀態。

redis> SCRIPT LOAD "return 'hello moto'"    # 載入一個指令碼"232fd51614574cf0867b83d384a5e898cfd24e5a"redis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a1) (integer) 1redis> SCRIPT FLUSH     # 清空緩衝OKredis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a1) (integer) 0
SCRIPT FLUSH

清除所有 Lua 指令碼緩衝。
關於使用 Redis 對 Lua 指令碼進行求值的更多資訊,請參見 EVAL 命令。
可用版本:
2.6.0
複雜度:
O(N) , N 為緩衝中指令碼的數量。
傳回值:
總是返回 OK

redis> SCRIPT FLUSHOK
SCRIPT KILL

殺死當前正在啟動並執行 Lua 指令碼,若且唯若這個指令碼沒有執行過任何寫操作時,這個命令才生效。
這個命令主要用於終止已耗用時間過長的指令碼,比如一個因為 BUG 而發生無限 loop 的指令碼,諸如此類。
SCRIPT KILL 執行之後,當前正在啟動並執行指令碼會被殺死,執行這個指令碼的用戶端會從 EVAL 命令的阻塞當中退出,並收到一個錯誤作為傳回值。
另一方面,假如當前正在啟動並執行指令碼已經執行過寫操作,那麼即使執行 SCRIPT KILL ,也無法將它殺死,因為這是違反 Lua 指令碼的原子性執行原則的。在這種情況下,唯一可行的辦法是使用 SHUTDOWN NOSAVE 命令,通過停止整個 Redis 進程來停止指令碼的運行,並防止不完整(half-written)的資訊被寫入資料庫中。
關於使用 Redis 對 Lua 指令碼進行求值的更多資訊,請參見 EVAL 命令。
可用版本:
2.6.0
時間複雜度:
O(1)
傳回值:
執行成功返回 OK ,否則返回一個錯誤。
沒有指令碼在執行時

redis> SCRIPT KILL(error) ERR No scripts in execution right now.

成功殺死指令碼時

redis> SCRIPT KILLOK(1.30s)

嘗試殺死一個已經執行過寫操作的指令碼,失敗

redis> SCRIPT KILL(error) ERR Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in an hard way using the SHUTDOWN NOSAVE command.(1.69s)

以下是指令碼被殺死之後,返回給執行指令碼的用戶端的錯誤:

redis> EVAL "while true do end" 0(error) ERR Error running script (call to f_694a5fe1ddb97a4c6a1bf299d9537c7d3d0f84e7): Script killed by user with SCRIPT KILL...(5.00s)
SCRIPT LOAD script

將指令碼 script 添加到指令碼緩衝中,但並不立即執行這個指令碼。
EVAL 命令也會將指令碼添加到指令碼緩衝中,但是它會立即對輸入的指令碼進行求值。
如果給定的指令碼已經在緩衝裡面了,那麼不做動作。
在指令碼被加入到緩衝之後,通過 EVALSHA 命令,可以使用指令碼的 SHA1 校正和來調用這個指令碼。
指令碼可以在緩衝中保留無限長的時間,直到執行 SCRIPT FLUSH 為止。
關於使用 Redis 對 Lua 指令碼進行求值的更多資訊,請參見 EVAL 命令。
可用版本:
2.6.0+
時間複雜度:
O(N) , N 為指令碼的長度(以位元組為單位)。
傳回值:
給定 script 的 SHA1 校正和

redis> SCRIPT LOAD "return 'hello moto'""232fd51614574cf0867b83d384a5e898cfd24e5a"redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0"hello moto"

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.