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;

showtooltip

上一篇:了解状态机之前先掌握跳转表


下一篇:linux c++(IO & 第五篇 软硬链接)