Redis服務器上使用強大的lua語言會如何?可能你已經聽說過Redis 中嵌入了腳本語言,但是你還沒有親自去嘗試吧? 下面我們就來嘗試一翻吧。
Hello, Lua!
我們的第一個Redis Lua 腳本僅僅返回一個字符串,而不會去與redis 以任何有意義的方式交互。
?
?
這是非常簡單的,第一行代碼定義了一個本地變量msg存儲我們的信息, 第二行代碼表示 從redis 服務端返回msg的值給客戶端。 保存這個文件到hello.lua,像這樣去運行:
?
?
運行這段代碼會打印"Hello,world!", EVAL在第一個參數是我們的lua腳本, 這我們用cat命令從文件中讀取我們的腳本內容。第二個參數是這個腳本需要訪問的Redis 的鍵的數字號。我們簡單的 “Hello Script" 不會訪問任何鍵,所以我們使用0
訪問鍵和參數
假設我們要建立一個URL簡寫服務器。我們就要去存儲每條進入的URL并返回一個唯一數值,以便以后通過這個數值訪問到該URL。
我們將利用Lua腳本立即從Redis中用INCRand獲取一個唯一標識ID,以這個標識ID作為URL存儲于一個哈希中的鍵值:
?
?
我們將用call()函數首次訪問Redis。call()的參數就是發給Redis的命令:首先INCR
我們將會訪問兩個Lua表:KEYS和ARGV。表單是關聯性數組和結構化數據的Lua唯一機制。對于我們的意圖,你可以把它們看做是一個你所熟悉的任意語言對等的數組,但是提醒兩個很容易困擾到新手的兩個Lua定則:
當調用這個腳本時,我們還需要傳遞KEYS和ARGV表的值:
?
?
在EVAL語句中,2指出需要傳入的KEY的個數,后面跟著需要傳入的兩個KEY,最后傳入是ARGV的值。在Redis中執行Lua腳本時,Redis-cli會檢查傳入KEY的個數,除非傳入的完全是命令。
為了解釋得更清楚,下面列出替換KEY和ARGV后的腳本:
?
?
為Redis編寫Lua腳本時,每個KEY都是通過KEYS表指定。ARGV表用來傳遞參數,這個例子中ARGV用來傳入URL。
邏輯條件:increx與hincrex
上一個例子保存鏈接為短網址,想要知道這個鏈接的點擊次數,在Redis中添加一個hash計數器。當帶有鏈接標記的用戶訪問時,我們檢查其是否存在,如存在則需要給計數器加1:
?
?
每次有人點擊短網址,我們運行這個腳本跟蹤這個鏈接被再次分享。我們用EVAL來調用腳本,傳入inlinks:visits(keys[1])和上一個腳本返回的鏈接標識(ARGV[1])。
這段腳本將檢查是否存在相同的hash,如果存在就為這個標準的Redis KEY加1。
?
?
腳本加載與注冊執行
注意,當Redis在運行Lua腳本的時候,其它的事情什么都干不了!腳本最好只是簡單的擴展Redis進行較小的原子操作和簡單的邏輯控制需要,Lua腳本中的bug可能引發整個Redis服務器鎖—最好保持腳本的簡短和易于調試。
雖然這些腳本一般都比較短小,但我們還是希望不要每次執行時都使用完整的Lua腳本,實際上可以在程序一步一步(譯注:application boots翻譯有難度)開發中注冊Lua腳本(或者在你部署時注冊),然后用注冊后生成的SHA-1標識來進行調用。
?
?
顯示調用SCRIPT LOAD通常是不必要的,當一個程序執行EVAL時就已隱式加載了。程序會先嘗試EAVALSHA,當腳本沒有找到時會調用EVAL。
對于Ruby開發者,可以看一下Shopify's Wolverine,其可以為Ruby應用簡單的加載并存儲Lua腳本。對于PHP開發者,Predis 支持加載Lua腳本作為普通Redis命令進行調用(譯注:需要繼承Predis/Command/ScriptedCommand基類,并注冊命令)。如果你使用這些或者其它的工具來標準化與Lua的交互,請讓我知道,我很感興趣知道本文之外的內容。
何時使用Lua
Redis支持WATCH/MULTI/EXEC這樣的塊,能進行一組操作,也能一起提交執行,看起來與Lua有重疊。應該如何進行選擇?MULT塊中所有操作獨立,但在Lua中,后面的操作能依賴前面操作的執行結果。同時使用Lua腳本還能夠避免WATCH使用后競爭條件引起客戶端反應變慢的情況。
在RedisGreen(譯注:國外一家專門提供Redis主機的服務商),我們看到許多應用使用Lua的同時也使用MULTI/EXEC,但兩者但不是替代關系。許多成功的Lua腳本都很小,僅僅實現一個你的應用需要而Redis命令中沒有單一的功能。
訪問庫
Redis的Lua解釋器加載七個庫:base,table,string, math, debug,cjson和cmsgpack。前幾個都是標準庫,充許你使用任何語言進行基本的操作。后面兩個可以讓Redis支持JSON和MessagePack—這是非常有用的功能,同時我也很想知道為什么常常看不到這種用法。
Web應用程序常常使用JSON作為api返回數據,你也許也可以把一堆JSON數據存到Redis的key中。當想訪問某些JSON數據時,首先需要保存到一個hash中,使用Redis的JSON支持將非常方便:
?
?
在這里我們檢查看key是否存在,如不存在則快速返回nil。如存在則從Redis中獲取JSON值,用cjson.decode()進行解析,然后返回請求內容。
?
?
加載這段腳本進你的Redis服務器,將JSON數據保存到Redis中,通常是hash。 雖然我們每次訪問時都必須解析,但只要你的對象很小,這個操作實際上是非常快的。
如果你的API只是在內部提供,通常需要考慮效率上的問題,MessagePack 是比采用JSON更好的選擇,它更小,更快,在Redis(更多場合也是如此),MessagePack是JSON更好的替代品。
?
?
數值轉換
Lua和Redis各有自己的一套類型,因此,理解Redis與Lua在邊界調用相互轉換引起值的改變是非常重要的。一個來自Lua中number返回到Redis客戶端時變成了integer—任何數字后面的小數點都被清除了:
?
?
在你運行這段腳本時,Redis將返回一個整數3,丟失了pi中有用的片段。看起來很簡單,但是一旦開始進行Redis與中間腳本交互時就需要更小心。例如:
?
?
執行的結果是一個字符串:“3.2”,這是為什么呢?在Redis中沒有專有的數值類型,當我們第一次調用SET的時候,Redis就已經將它保存為字符串了,將Lua初始化時將其作為一個浮點數的類型信息給丟失了。所以當我們后面取出這個值時,它就變成了一個字符串。
在Redis中,除了INCR和DECR,其它的GET,SET操作所訪問的數據都作為字符串處理。INCR與DECR是專門對數值的操作,實際上返回是整數(integer)回復(維護和存儲遵守數字規則),但Redis內部保存類型實際上還是字符串值。
總結:
下面這些都是在Redis中使用Lua時常見的錯誤:
以上就是Redis服務器上使用強大的lua語言會如何的全部內容,更多關于Redis的內容,可以多多關注下武林技術頻道。
新聞熱點
疑難解答
圖片精選