lua+redis

在使用redis分佈式鎖時,爲了保證加鎖解鎖具備原子性

加鎖時使用帶過期時間的set指令,而不是通過setnx+expire;

解鎖時爲了防止誤刪,給鎖添加了唯一標識,判斷唯一標識與解鎖之間也要具備原子性,使用lua腳本解決

redis中使用lua腳本的方式;EVAL script numkeys key [key...] arg [arg...]

    script:腳本語言

    numkeys :key的數量。必須要指定

    key :key的值

    arg :value的值。因爲redis存儲的key:value的方式

通過EVAL “lua腳本” 即可實現

例如:

    EVAL "if 1>0 then return 1 else retrun 0 end"0

    EVAL "if KEYS[1]>ARGV[1] then return 1 else retrun 0 end" 1 1 0

        表示:keys裏的第一個值是1>agev裏的第一個值0

通過lua腳本操作redis:通過redis.call()

    EVAL "retrun redis.call('get',KEYS[1])" 1 lock 

    redis.call(redis的命令,查詢的key)

        查詢的key:不能寫死,例如redis.call('get','lock'),只能通過後面的key參數指定

    根據鎖的唯一標識刪除鎖實現原子性

        if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

不可重入  

加鎖

if (redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 1) 
then
    redis.call('hincrby', KEYS[1], ARGV[1], 1);
    redis.call('expire', KEYS[1], ARGV[2]);
    return 1;
else
	return 0;
end

    redis中

        exists key:判斷鎖是否存在,不存在返回0,存在返回1

        hexists key filed:判斷是不是自己的鎖。hexists  lock 12345 ,返回1說明這個uuid是12345的鎖是當前線程自己的鎖

解鎖

-- 判斷 hash set 可重入 key 的值是否等於 0
-- 如果爲 nil 代表 自己的鎖已不存在,在嘗試解其他線程的鎖,解鎖失敗
-- 如果爲 0 代表 可重入次數被減 1
-- 如果爲 1 代表 該可重入 key 解鎖成功
if (redis.call('hexists', KEYS[1], ARGV[1]) == 0) then
    return nil;
end;
-- 小於等於 0 代表可以解鎖
if (redis.call('hincrby', KEYS[1], ARGV[1], -1) > 0) then
    return 0;
else
    redis.call('del', KEYS[1]);
    return 1;
end;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章