Redis(六)Lua指令碼的支援

來源:互聯網
上載者:User

標籤:函數調用   語言   uri   redis   第一個   argv   清除   命令操作   val   

Redis為什麼需要Lua指令碼的支援

當應用需要Redis完成一些Redis命令不支援的特性時,要麼擴充Redis client或者更甚至編寫c擴充Redis server。這都大大造成了應用的實現的難度。在此基礎上,Redis通過內建Lua解譯器,Redis client可以發起執行Lua指令碼,完成特殊的功能需求。

Redis中使用Lua指令碼

在Redis中可以通過使用eval和evalsha命令提供對執行Lua的支援。

eval文法:

EVAL script numkeys key [key ...] arg [arg ...]

  • script是lua指令碼;
  • numkeys是lua指令碼中key的數量;
  • key是多選,即lua指令碼中可以操作多個key;
  • arg是多選,供lua基本執行時提供參數;

在lua指令碼中可以通過全域變數KEYS和ARGV擷取key和arg。KEYS和ARGV都是數組,KEYS[1],KEYS[2],...等等,基數從1開始,按照順序擷取後面的key。ARGV同理。

如:

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

上面返回key1和key2的value,並且返回連個參數。

Redis提供了兩個不同的Lua函數調用執行Redis命令:

  • redis.call():當redis命令執行錯誤時,將會返回錯誤;
  • redis.pcall:當redis命令執行錯誤時,將會捕獲異常,返回一個帶有錯誤域的Lua表;

如:

127.0.0.1:6380>  lpush foo a(integer) 1127.0.0.1:6380> eval "return redis.call(‘get‘,‘foo‘)" 0(error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): @user_script:1: WRONGTYPE Operation against a key holding the wrong kind of value127.0.0.1:6380> EVAL "return redis.pcall(‘get‘, ‘foo‘)" 0(error) WRONGTYPE Operation against a key holding the wrong kind of value

Lua指令碼作為一種指令碼語言,有自己的資料類型,Redis也有自己的資料類型。在Lua指令碼和Redis命令操作的之間切換時,必然會涉及資料類型的轉化。

資料類型之間的轉換遵循這樣一個設計原則:Redis調用Lua解譯器執行指令碼時,會將Redis類型轉化成Lua類型;當Lua指令碼執行後,傳回值時,會將傳回值轉化成Redis類型,eval再將Lua指令碼返回給client。

具體的對應細節參考:Lua 資料類型和 Redis 資料類型之間轉換。

Redis中Lua指令碼帶來的收益

原子性:Redis使用單個Lua解譯器去運行所有指令碼,並且Redis也保證指令碼會以原子性的方式執行:當某個指令碼正在啟動並執行時候,不會有其他指令碼或Redis命令被執行。這和使用MULTI/EXEC包圍的事務很類似。在其他別的用戶端看來,指令碼的效果要麼是不可見的,要麼就是已完成的。另一方面,這也意味著,執行一個運行緩慢的指令碼並不是一個好主意。寫一個跑得很快很順溜的指令碼並不難,因為指令碼的運行開銷非常少,但是當你不得不使用一些跑得比較慢的指令碼時,請小心,因為當這些蝸牛指令碼在慢吞吞地啟動並執行時候,其他用戶端會因為伺服器正忙而無法執行命令。

緩衝指令碼:eval命令要求每次每次執行lua指令碼時,都需要發送lua指令碼至伺服器,雖然redis緩衝機制保證不會重新編譯lua指令碼,但是每次都傳輸指令碼主體,無疑是消耗帶框。為了減少帶框,Redis使用evalsha命令發起lua指令碼,但是evalsha的第一個參數不是lua指令碼,而是指令碼所對應的shasum校正和值。

如:

127.0.0.1:6380> set foo barOK127.0.0.1:6380> 127.0.0.1:6380> 127.0.0.1:6380> eval "return redis.call(‘get‘,‘foo‘)" 0"bar"127.0.0.1:6380> evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0"bar"

用戶端庫的底層實現可以一直樂觀地使用 EVALSHA 來代替 EVAL ,並期望著要使用的指令碼已經儲存在伺服器上了,只有當 NOSCRIPT 錯誤發生時,才使用 EVAL 命令重新發送指令碼,這樣就可以最大限度地節省頻寬。

Redis提供的SCRIPT命令
  • script flush:清除所有指令碼緩衝;
  • script exists:根據給定的指令碼校正和,判斷指令碼是否存在;
  • script load:將一個指令碼載入記憶體,但是不運行;
  • script kill:殺死一個正在執行的指令碼程式;
參考

https://redis.io/commands/eval

Redis(六)Lua指令碼的支援

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.