天天看點

Redis Lua腳本

Redis Lua腳本

  • script: 一段Lua 5.1 腳本程式,這段腳本不必定義為一個Lua函數
  • numkeys:鍵名參數的個數
  • 要求使用正确的形式來傳遞鍵(key)是有原因的,因為不僅僅是 EVAL 這個指令,所有的 Redis 指令,在執行之前都會被分析,籍此來确定指令會對哪些鍵進行操作。

示例:

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

腳本的原子性

Redis 使用單個 Lua 解釋器去運作所有腳本,并且, Redis 也保證腳本會以原子性(atomic)的方式執行:當某個腳本正在運作的時候,不會有其他腳本或 Redis 指令被執行。相當于事務,事務還有可能被lua腳本替代。

特别注意:如果這個lua腳本執行很慢,會嚴重影響其他腳本運作

Lua腳本中執行Redis指令

主要是這兩個函數:

  • redis.call() 直接抛出Redis異常,執行腳本出錯
  • redis.pcall() 會捕獲異常,并傳回錯誤資訊

    示例:

redis> eval "return redis.call('get', KEYS[1])" 1 foo
           

EVALSHA

  • sha1 是lua腳本的SHA1校驗碼,相當于腳本的身份id
  • Redis會緩存每次執行的腳本,并永久備份(除非手動清除),下次執行相同腳本,可以用sha1代替,而不是每次都傳腳本内容(可能會很長),來節省寬帶

EVALSHA 指令的表現如下:

  • 如果伺服器還記得給定的 SHA1 校驗和所指定的腳本,那麼執行這個腳本
  • 如果伺服器不記得給定的 SHA1 校驗和所指定的腳本,那麼它傳回一個特殊的錯誤,提醒使用者使用 EVAL 代替 EVALSHA

使用Lua腳本的好處

  • 減少網絡開銷:使用腳本,一次性執行多個指令,減少網絡請求,減少了網絡往返時延。
  • 原子操作:Redis會将整個腳本作為一個整體執行,中間不會被其他指令插入。
  • 複用:用戶端發送的腳本會永久存儲在Redis中,意味着其他用戶端可以複用這一腳本而不需要使用代碼完成同樣的邏輯。

使用Lua腳本注意事項

Lua腳本應該具備以下屬性:

對于同樣的資料集輸入,給定相同的參數,腳本執行的 Redis 寫指令總是相同的。腳本執行的操作不能依賴于任何隐藏(非顯式)資料,不能依賴于腳本在執行過程中、或腳本在不同執行時期之間可能變更的狀态,并且它也不能依賴于任何來自 I/O 裝置的外部輸入
為了防止不必要的資料洩漏進 Lua 環境, Redis 腳本不允許建立全局變量

為了保證符合上面要求,Redis做了一下工作:

  • Lua沒喲通路系統時間或其他内部狀态的指令
  • 每當傳回無序元素時,會進行字典序排序,以保證資料傳回結果一緻
  • 對Lua的僞随機函數進行修改,使得每次運作總有相同的seed值,這樣産生的随機數序列都是相同的。

繼續閱讀