Redission 分布式锁原理Redission 是一redis客户端和jedis、lettuce 一样,但他提供诸多如分布式锁这些方便的工具加锁过程lua脚本
加锁过程 
lua脚本:
1 2 3 4 5 6 7 8 9 10 11
| "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);"
|
1、如果锁不存在:使用hest方法创建了锁,filed是线程的唯一标识 value 是重入次数 ,初始为1
2、如果锁存在且为自身持有:使用hincrby 将value加1表示发生了一次重入
3、如果锁存在但非自身持有:返回锁的过期时间(毫秒级别)
用setnx实现的分布式锁中存在着一个这样的问题:锁无法续期
redission为我们提供的锁的默认时间是30秒,并且在客户端加锁成功后会启动一个watch dog后台线程,每隔10秒检查一下,如果客户端还持有锁key,那么就会不断的延长锁key的生存时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| if (redis.call('exists', KEYS[1]) == 0) then redis.call('publish', KEYS[2], ARGV[1]); return 1; end;
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil; end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); return 0; else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; return nil;
|
 总结:
1、redission自带的分布式锁作为附带的工具可以很好的满足我们在分布式系统上的加锁需求
2、相较于setnx 实现的分布式锁,其实现原理更为复杂一些,引入了watch dog机制,实现了锁的可续期
3、无论是redission还是setnx实现的分布式锁,在redis的集群模式下,都存在主节点故障导致的问题:妙的利用hash 结构实现了锁的可重入
4、无论是redission还是setnx实现的分布式锁,在redis的集群模式下,都存在主节点故障导致的问题:A客户端在主节点写入自己的锁,此时主节点宕机,该数据未及时同步到从节点,而后从节点被选举为主节点,B客户端如果也去写入锁,同样能够成功,此时存在并发写入导致的系列风险问题