雖然redis服務是單線程的服務,單步的redis操作是線程安全的,但是當我們在高并發(fā)的情況下,需要一系列的redis邏輯操作,而這些操作需要保證線程安全和原子性。這時候就需要Lua登場。
Lua 為靜態(tài)語言提供更多的靈活性,Lua體積小、啟動速度快。 Redis Lua 腳本出現(xiàn)之前 Redis 是沒有服務器端運算能力的,主要是用來存儲,用做緩存,運算是在客戶端進行。有了 Lua 的支持,客戶端可以定義對鍵值的運算,減少編譯的次數(shù),總之??梢宰?Redis 更為靈活。redis 甚至在源代碼中加入了Lua腳本的解釋器,eval。
redis 缺點
- 如此會破壞數(shù)據(jù)的一致性,試想如果兩個客戶端先后獲?。╣et)一個值,它們分別對鍵值做不同的修改,然后先后提交結(jié)果,最終 Redis 服務器中的結(jié)果肯定不是某一方客戶端所預期的。
- 浪費了數(shù)據(jù)傳輸?shù)木W(wǎng)絡帶寬。
基本概念
1. Redis 2.6.0
- 從Redis 2.6.0 開始, Redis在服務器端內(nèi)置Lua解釋器,支持通過Lua腳本操作Redis
2. EVAL
- 通過Lua操作Redis最常用的命令之一, 第一個參數(shù) Lua腳本
3. EVALSHA
- 通過Lua操作Redis最常用的命令之一, 第一個參數(shù)是Lua腳本生成的SHA值; 可以節(jié)省帶寬
4. 串行
- Lua腳本在Redis服務器端是串行執(zhí)行的,因此可以實現(xiàn)類似事務的功能。
最簡單的Lua腳本
hello.lua
local msg = "hello world!"
return msg
運行命令
redis-cli -h ****(ip) -p ***(port) eval "$(cat hello.lua)" 0
運行這段代碼會打印"Hello,world!", EVAL在第一個參數(shù)是我們的lua腳本, 這我們用cat命令從文件中讀取我們的腳本內(nèi)容。第二個參數(shù)是這個腳本需要訪問的Redis 的鍵的數(shù)字號。我們簡單的 “Hello Script" 不會訪問任何鍵,所以我們使用 0
get和set 的例子
getSet.lua
local key = KEYS[1]
local value = ARGV[1]
redis.call('set', key, value)
return redis.call('get', key)
運行命令
redis-cli -h ****(ip) -p ***(port) eval "$(cat getSet.lua)" 1 age 18

call() 的參數(shù)就是發(fā)給Redis的命令:首先set key value ,然后 get key,這兩個命令將依次執(zhí)行,當這個腳本執(zhí)行時,Redis服務不會做任何操作(單線程),它將非??焖龠\行。
我們將會訪問兩個Lua表:KEYS和ARGV。表單是關聯(lián)性數(shù)組和結(jié)構(gòu)化數(shù)據(jù)的Lua唯一機制。對于我們的意圖,你可以把它們看做是一個你所熟悉的任意語言對等的數(shù)組,但是提醒兩個很容易困擾到新手的兩個Lua定則:
表是基于1的,也就是說索引以數(shù)值1開始。所以在表中的第一個元素就是KEYS[1],第二個就是KEY[2]等等。
表中不能有nil值。如果一個操作表中有[1, nil, 3, 4],那么結(jié)果將會是[1]——表將會在第一個nil截斷。
當調(diào)用這個腳本時,我們還需要傳遞KEYS和ARGV表的值,為Redis編寫Lua腳本時,每個KEY都是通過KEYS表指定。ARGV表用來傳遞參數(shù)。