雖然redis服務(wù)是單線程的服務(wù)驴剔,單步的redis操作是線程安全的届巩,但是當(dāng)我們?cè)诟卟l(fā)的情況下旱易,需要一系列的redis邏輯操作峦朗,而這些操作需要保證線程安全和原子性建丧。這時(shí)候就需要Lua登場。
Lua 為靜態(tài)語言提供更多的靈活性波势,Lua體積小翎朱、啟動(dòng)速度快。 Redis Lua 腳本出現(xiàn)之前 Redis 是沒有服務(wù)器端運(yùn)算能力的尺铣,主要是用來存儲(chǔ)拴曲,用做緩存,運(yùn)算是在客戶端進(jìn)行凛忿。有了 Lua 的支持澈灼,客戶端可以定義對(duì)鍵值的運(yùn)算,減少編譯的次數(shù),總之叁熔∥冢可以讓 Redis 更為靈活。redis 甚至在源代碼中加入了Lua腳本的解釋器荣回,eval遭贸。
redis 缺點(diǎn)
- 如此會(huì)破壞數(shù)據(jù)的一致性,試想如果兩個(gè)客戶端先后獲刃娜怼(get)一個(gè)值壕吹,它們分別對(duì)鍵值做不同的修改,然后先后提交結(jié)果糯累,最終 Redis 服務(wù)器中的結(jié)果肯定不是某一方客戶端所預(yù)期的算利。
- 浪費(fèi)了數(shù)據(jù)傳輸?shù)木W(wǎng)絡(luò)帶寬。
基本概念
1. Redis 2.6.0
- 從Redis 2.6.0 開始泳姐, Redis在服務(wù)器端內(nèi)置Lua解釋器效拭,支持通過Lua腳本操作Redis
2. EVAL
- 通過Lua操作Redis最常用的命令之一, 第一個(gè)參數(shù) Lua腳本
3. EVALSHA
- 通過Lua操作Redis最常用的命令之一胖秒, 第一個(gè)參數(shù)是Lua腳本生成的SHA值缎患; 可以節(jié)省帶寬
4. 串行
- Lua腳本在Redis服務(wù)器端是串行執(zhí)行的,因此可以實(shí)現(xiàn)類似事務(wù)的功能阎肝。
最簡單的Lua腳本
hello.lua
local msg = "hello world!"
return msg
運(yùn)行命令
redis-cli -h ****(ip) -p ***(port) eval "$(cat hello.lua)" 0
運(yùn)行這段代碼會(huì)打印"Hello,world!", EVAL在第一個(gè)參數(shù)是我們的lua腳本挤渔, 這我們用cat命令從文件中讀取我們的腳本內(nèi)容。第二個(gè)參數(shù)是這個(gè)腳本需要訪問的Redis 的鍵的數(shù)字號(hào)风题。我們簡單的 “Hello Script" 不會(huì)訪問任何鍵判导,所以我們使用 0
get和set 的例子
getSet.lua
local key = KEYS[1]
local value = ARGV[1]
redis.call('set', key, value)
return redis.call('get', key)
運(yùn)行命令
redis-cli -h ****(ip) -p ***(port) eval "$(cat getSet.lua)" 1 age 18
call() 的參數(shù)就是發(fā)給Redis的命令:首先set key value
,然后 get key
,這兩個(gè)命令將依次執(zhí)行沛硅,當(dāng)這個(gè)腳本執(zhí)行時(shí)眼刃,Redis服務(wù)不會(huì)做任何操作(單線程),它將非骋〖。快速運(yùn)行擂红。
我們將會(huì)訪問兩個(gè)Lua表:KEYS
和ARGV
。表單是關(guān)聯(lián)性數(shù)組和結(jié)構(gòu)化數(shù)據(jù)的Lua唯一機(jī)制围小。對(duì)于我們的意圖昵骤,你可以把它們看做是一個(gè)你所熟悉的任意語言對(duì)等的數(shù)組,但是提醒兩個(gè)很容易困擾到新手的兩個(gè)Lua定則:
表是基于1的肯适,也就是說索引以數(shù)值1開始变秦。所以在表中的第一個(gè)元素就是KEYS[1]
,第二個(gè)就是KEY[2]
等等框舔。
表中不能有nil
值伴栓。如果一個(gè)操作表中有[1, nil, 3, 4]
,那么結(jié)果將會(huì)是[1]——表將會(huì)在第一個(gè)nil截?cái)唷?br>
當(dāng)調(diào)用這個(gè)腳本時(shí),我們還需要傳遞KEYS
和ARGV
表的值钳垮,為Redis編寫Lua腳本時(shí),每個(gè)KEY都是通過KEYS表指定额港。ARGV表用來傳遞參數(shù)饺窿。