加锁
- 生成一个非凡值(比方随机值+以后线程ID),记录在在ThreadLocal里。
- 通过setnx向特定的key写入第一步生成的随机值,同时设置生效工夫,操作胜利则代表加锁胜利。
SET resource_name my_random_value NX PX 30000
阐明
- 设置一个生效工夫是为了防止死锁。
- 写入一个随机值是为了防止加锁与解锁是同一线程
- 写入随机值与设置生效工夫是同时的是为了保障加锁是原子操作。
解锁
依据key获得随机值,从ThreadLocal里取出随机数,进行二者判断,删除redis上的key数据,要保障获取数据、判断随机值是否匹配及删除数据这三个操作是原子的,可通过lua脚本实现。
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1])else return 0end
潜在的问题:过期工夫设多长?
设置过小,有可能上一个线程还没执行完锁的逻辑锁就开释了,另一个线程获取锁而后呈现并发问题。
设置过大,如果客户端断线了,这个锁要期待很长时间。
这个问题Redisson提供了主动延期机制也就是watch dog。
Redisson中客户端一旦加锁胜利,如果客户端没有被动设置生效工夫就会启动一个watch dog看门狗。watch dog是一个后盾线程,会每隔10s(可配置)检查一下,如果客户端还持有锁key,那么就会一直的缩短锁key的生存工夫。
如果客户端呈现了宕机,那客户端加的锁会怎么样呢?首先因为续锁线程(一个定时工作)和加锁线程同在一个JVM实例里,机器宕机后续锁线程也会挂掉所以不会呈现始终续期的情景。另外在在客户端没有设置生效工夫,Redisson会有一个默认的过期工夫30s(也能够通过Config.lockWatchdogTimeout配置进行调整),因为续期线程已不存在,所以到了工夫后天然会删除锁,这样就不会存在死锁的情景。
另外须要阐明下,线程被中断或在续期过程中设置过期工夫失败都会开释锁。
这个计划是目前最优的分布式锁计划,然而如果在Redis集群环境下仍然存在问题:
因为Redis集群数据同步为异步,假如在Master节点获取到锁后未实现数据同步状况下Master节点crash,此时在新的Master节点仍然能够获取锁,所以多个Client同时获取到了锁。针对这个问题,之前提出了Redlock解决方案,不过当初已被官网弃用了,起因是Redisson RedLock 是基于联锁 MultiLock 实现的,然而应用过程中须要本人判断 key 落在哪个节点上,对使用者不是很敌对。这个是被弃用的阐明:Redlock弃用起因,上面是英文文档:
https://github.com/redisson/r...
8.4. RedLockThis object is deprecated. RLock operations now propagated to all Redis slaves.
参考的文档:
RedissonBaseLock源码
Redisson分布式锁源码剖析
Redlock的阐明
Redlock源码
Redlock源码剖析
Redisson锁续期定制化调整
Redisson重连后WatchDog生效问题解决
Redisson阐明文档