(轉) Lua: 給 Redis 使用者的入門指導

來源:互聯網
上載者:User

標籤:style   http   color   使用   io   strong   資料   ar   

可能你已經聽說過Redis 中嵌入了指令碼語言,但是你還沒有親自去嘗試吧?  這個入門教程會讓你學會在你的Redis 伺服器上使用強大的lua語言。

Hello, Lua!

我們的第一個Redis Lua 指令碼僅僅返回一個字串,而不會去與redis 以任何有意義的方式互動。
1 local msg = "Hello, world!"

view source
print?

1 local link_id = redis.call("INCR", KEY[1])

2 redis.call("HSET", KEYS[2], link_id, ARGV[1])

3 return link_id


 

我們將用call()函數首次訪問Redis。call()的參數就是發給Redis的命令:首先INCR <key>, 然後HSET <key> <field> <value>。這兩個命令將依次執行——當這個指令碼執行時,Redis不會做任何事,它將非常快地運行。我們將會訪問兩個Lua表:KEYS和ARGV。表單是關聯性數組和結構化資料的Lua唯一機制。對於我們的意圖,你可以把它們看做是一個你所熟悉的任意語言對等的數組,但是提醒兩個很容易困擾到新手的兩個Lua定則:

 

  • 表是基於1的,也就是說索引以數值1開始。所以在表中的第一個元素就是mytable[1],第二個就是mytable[2]等等。
  • 表中不能有nil值。如果一個動作表中有[1, nil, 3, 4],那麼結果將會是[1]——表將會在第一個nil截斷。
當調用這個指令碼時,我們還需要傳遞KEYS和ARGV表的值:
1 redis-cli EVAL "$(cat incr-and-stor.lua)"2 links:counter links:urls http://malcolmgladwellbookgenerator.com/


 

在EVAL語句中,2指出需要傳入的KEY的個數,後面跟著需要傳入的兩個KEY,最後傳入是ARGV的值。在Redis中執行Lua指令碼時,Redis-cli會檢查傳入KEY的個數,除非傳入的完全是命令。為瞭解釋得更清楚,下面列出替換KEY和ARGV後的指令碼:view source
print?

1 local link_id = redis.call("INCR", "links:counter")

view source
print?

1 if redis.call("EXISTS",KEYS[1]) == 1 then

2 return redis.call("INCR",KEYS[1])

3 else

4 return nil

5 end
  指令碼載入與註冊執行注意,當Redis在運行Lua指令碼的時候,其它的事情什麼都幹不了!指令碼最好只是簡單的擴充Redis進行較小的原子操作和簡單的邏輯控制需要,Lua指令碼中的bug可能引發整個Redis伺服器鎖—最好保持指令碼的簡短和易於調試。雖然這些指令碼一般都比較短小,但我們還是希望不要每次執行時都使用完整的Lua指令碼,實際上可以在程式一步一步(譯註:application boots翻譯有難度)開發中註冊Lua指令碼(或者在你部署時註冊),然後用註冊後產生的SHA-1標識來進行調用。view source
print?

1 redis-cli SCRIPT LOAD "return ‘hello world‘"

 
3

 



指令碼載入與註冊執行注意,當Redis在運行Lua指令碼的時候,其它的事情什麼都幹不了!指令碼最好只是簡單的擴充Redis進行較小的原子操作和簡單的邏輯控制需要,Lua指令碼中的bug可能引發整個Redis伺服器鎖—最好保持指令碼的簡短和易於調試。雖然這些指令碼一般都比較短小,但我們還是希望不要每次執行時都使用完整的Lua指令碼,實際上可以在程式一步一步(譯註:application boots翻譯有難度)開發中註冊Lua指令碼(或者在你部署時註冊),然後用註冊後產生的SHA-1標識來進行調用。view source
print?

1 redis-cli SCRIPT LOAD "return ‘hello world‘"

 
3

 


何時使用LuaRedis支援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支援將非常方便:view source
print?

1 if redis.call("EXISTS", KEYS[1]) == 1 then

2 local payload = redis.call("GET", KEYS[1])

3 return cjson.decode(payload)[ARGV[1]]

4 else

5 return nil

6 end



在這裡我們檢查看key是否存在,如不存在則快速返回nil。如存在則從Redis中擷取JSON值,用cjson.decode()進行解析,然後返回請求內容。
1 redis-cli set apple ‘{ "color": "red", "type": "fruit" }‘

2 => OK

3

 
載入這段指令碼進你的Redis伺服器,將JSON資料儲存到Redis中,通常是hash。 雖然我們每次訪問時都必須解析,但只要你的對象很小,這個操作實際上是非常快的。如果你的API只是在內部提供,通常需要考慮效率上的問題,MessagePack 是比採用JSON更好的選擇,它更小,更快,在Redis(更多場合也是如此),MessagePack是JSON更好的替代品。view source
print?

1 if redis.call("EXISTS", KEYS[1]) == 1 then

2 local payload = redis.call("GET", KEYS[1])

3 return cmsgpack.unpack(payload)[ARGV[1]]

4 else

5 return nil

6 end



數值轉換Lua和Redis各有自己的一套類型,因此,理解Redis與Lua在邊界調用相互轉換引起值的改變是非常重要的。一個來自Lua中number返回到Redis用戶端時變成了integer—任何數字後面的小數點都被清除了:view source
print?

1 local indiana_pi = 3.2

2 return indiana_pi



在你運行這段指令碼時,Redis將返回一個整數3,丟失了pi中有用的片段。看起來很簡單,但是一旦開始進行Redis與中間指令碼互動時就需要更小心。例如:
1 local indiana_pi = 3.2

2 redis.call("SET", "pi", indiana_pi)

3 return redis.call("GET", "pi")



執行的結果是一個字串:“3.2”,這是為什麼呢?在Redis中沒有專有的數實值型別,當我們第一次調用SET的時候,Redis就已經將它儲存為字串了,將Lua初始化時將其作為一個浮點數的類型資訊給丟失了。所以當我們後面取出這個值時,它就變成了一個字串。在Redis中,除了INCR和DECR,其它的GET,SET操作所訪問的資料都作為字串處理。INCR與DECR是專門對數值的操作,實際上返回是整數(integer)回複(維護和儲存遵守數字規則),但Redis內部檔案類型實際上還是字串值。
總結:下面這些都是在Redis中使用Lua時常見的錯誤:
  • 表是Lua中的運算式,與很多流行語言不同。KEYS中的第一個元素是KEYS[1],第二個是KEYS[2](譯註:不是0開始)
  • nil是表的結束符,[1,2,nil,3]將自動變為[1,2],因此在表中不要使用nil。
  • redis.call會觸發Lua中的異常,redis.pcall將自動捕獲所有能檢測到的錯誤並以表的形式返回錯誤內容。
  • Lua數字都將被轉換為整數,發給Redis的小數點會丟失,返回前把它們轉換成字串類型。
  • 確保在Lua中使用的所有KEY都在KEY表中,否則在將來的Redis版中你的指令碼都有不能被很好支援的危險。
  • Lua指令碼和其它Redis操作一樣,在指令碼執行時,其它的一切都不能運行。考慮用指令碼來護展Redis伺服器能力,但要保持短小和有用。
補充讀物 補充讀物下面有許多關於Lua和Redis很好的線上資源,本文只是我所用到的很少一部分:Lua Reference ManualLua Tutorial DirectoryEVAL Docsevalsha.com — 偶爾會有垃圾郵件,但內容很好(譯註:裡面有很多的Lua指令碼,以EVALSHA方式提供,超棒,希望對你有用。)
相關文章

聯繫我們

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