減少交互
原生接口支持豐富的數據結構,但對有些操作支持的不夠好。
比如在對key進行設置時,可以同時寫入超時時間。這樣在一條指令中就可以完成。
如果是incr操作,原生沒有提供超時時間參數,需要調用兩次接口實現。
可能產生的問題是,一是如果第一條操作后程序出現問題,導致超時時間沒有設置,則會造成redis內存無法釋放。二是多了一次網絡交互,會增加業務的響應延遲。
因此在使用lua腳本把兩條操作合并,可以達到減少交互的作用。
實現原子操作
redis本身是單線程執行,可以實現原子操作,但對于搶鎖這樣的業務,則無法用原生接口實現。
比如實現一個分布式鎖,加鎖過程可以使用set命令實現
red:set(key, name, "NX", "EX", ttl)
但是解鎖過程卻不能簡單使用del刪除,因為鎖有過期時間,過期后被其它人獲取到,再進行釋放就產生了bug。
所以先判斷是否自己再進行刪除
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
例可重入鎖的實現:
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('setex', KEYS[1], ARGV[2], ARGV[1]) else return redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2], 'nx') end
實現復雜邏輯
下面例子用zset實現時間戳隊列,更新超時時間的算法。當用兩次操作取出再放入時,會有丟數據風險,因此用腳本實現
redis.call('zrangebyscore', KEYS[1], ARGV[1], ARGV[2], 'limit', ARGV[3], ARGV[4])\
if #ret > 0 then\
local val = {}\
for i = 1, #ret do\
val[2 * i - 1] = ARGV[5]\
val[2 * i] = ret[i]\
end\
redis.call('zadd',KEYS[1],unpack(val))\
end\