1.lua簡介
從 Redis 2.6.0 版本開始,通過內(nèi)置的 Lua 解釋器,可以使用 EVAL 命令對 Lua 腳本進(jìn)行求值。
Redis 使用單個 Lua 解釋器去運(yùn)行所有腳本,并且, Redis 也保證腳本會以原子性(atomic)的方式執(zhí)行:當(dāng)某個腳本正在運(yùn)行的時候,不會有其他腳本或 Redis 命令被執(zhí)行。這和使用 MULTI / EXEC 包圍的事務(wù)很類似。在其他別的客戶端看來,腳本的效果(effect)要么是不可見的(not visible),要么就是已完成的(already completed)。
2.Lua腳本配置流程
在resource目錄下面新增一個后綴名為.lua結(jié)尾的文件
編寫腳本執(zhí)行內(nèi)容
調(diào)用redisTemplate.execute方法執(zhí)行腳本
3.lua eval:http://doc.redisfans.com//eval.html 4.本地起兩個服務(wù)節(jié)點(diǎn)作為演示。演示代碼如下:
本文采用定時調(diào)度模擬線程去獲取鎖(鏈接:詳解Scheduled定時調(diào)度)
使用-Dserver.port=9527,-Dserver.port=9528開啟多個節(jié)點(diǎn)
local lock_key = KEYS[1]
local lock_value = KEYS[2]
local result = redis.call(‘SETNX’,lock_key,lock_value)
if result == 1
then
redis.call(‘SETEX’,lock_key,60,lock_value)
return result
else
return result
end
lua腳本redis客戶端執(zhí)行命令如下:
redis-cli --eval xxxx.lua value value 。..。..。
ps:執(zhí)行成功返回1,失敗返回0
local lock_key = KEYS[1]
local lock_value = KEYS[2]
local lock_time_out = KEYS[3]
local result = redis.call(‘SET’,lock_key,lock_value,‘EX’,lock_time_out,‘NX’)
return result
ps:執(zhí)行成功返回OK,失敗返回nil
@Component
public class RedisLock {
@Autowired
private RedisTemplate redisTemplate;
private DefaultRedis《Boolean》 lock;
@Value(“${server.port}”)
private String port;
@Scheduled(cron = “0/5 * * * * *”)
public void lock {
String lock = “LockNxExJob”;
Boolean absent = false;
try {
// 獲取鎖
absent = luaExpress (lock, port);
if (!absent) {
System.out.println (String.format (“獲取鎖失敗!被%s拿走”, redisTemplate.opsForValue .get (lock)));
} else {
System.out.println (String.format (“獲取鎖成功!值為:%s”, redisTemplate.opsForValue .get (lock)));
}
} catch (Exception e) {
e.printStackTrace ;
} finally {
// 釋放鎖
if (absent) redisTemplate.delete (lock);
}
}
public Boolean luaExpress(String key, String value) {
lock = new DefaultRedis《》 ;
lock.setSource (new ResourceSource (new ClassPathResource (“l(fā)ua\redis.lua”)));
lock.setResultType (Boolean.class);
List《Object》 list = new ArrayList《》 ;
list.add (key);
list.add (value);
Boolean result = (Boolean) redisTemplate.execute (lock, list);
return result;
}
}
ps:當(dāng)節(jié)點(diǎn)9527成功獲取分布式鎖,在沒有執(zhí)行釋放鎖之前,服務(wù)節(jié)點(diǎn)宕掉了,節(jié)點(diǎn)9528則會無法獲取到鎖,直到設(shè)置鎖的超時時間結(jié)束,才能獲得鎖。避免了單節(jié)點(diǎn)掛掉了,鎖一直未被釋放的尷尬場景。
5.總結(jié)
Redis 使用單個 Lua 解釋器去運(yùn)行所有腳本,并且, Redis 也保證腳本會以原子性(atomic)的方式執(zhí)行:當(dāng)某個腳本正在運(yùn)行的時候,不會有其他腳本或 Redis 命令被執(zhí)行,保證了只要能setnx成功就能setex。解決了服務(wù)獲取鎖成功,但突然宕機(jī),未能設(shè)置超時時間問題。
責(zé)任編輯 LK
-
代碼
+關(guān)注
關(guān)注
30文章
4744瀏覽量
68345 -
Lua
+關(guān)注
關(guān)注
0文章
80瀏覽量
10543 -
Redis
+關(guān)注
關(guān)注
0文章
371瀏覽量
10845
發(fā)布評論請先 登錄
相關(guān)推薦
評論