问题:UUID和线程id作为key来防止释放其他线程的锁如何理解?
思考:
锁在redis中的格式:
key:共享资源的标识
value:UUID+线程ID
redis申请锁时会使用SET NX命令向redis数据库写入锁(key,value),写入成功则获得锁,失败则阻塞。
redis释放锁时会通过value值中的线程ID和释放锁的线程的ID进行对比,防止其他线程释放本线程的锁或本线程释放其他线程的锁。
SET NX特定,使用SET NX写入数据,redis会先查询数据库中是否存在当前key,存在返回false,不存在设置值后返回true。而由于redis是单线程的,不同客户端线程访问同一个redis服务器时,redis单线程操作,相当于把不同客户端的SET NX请求排了个队,先到达的SET NX执行后,后面的SET NX都会返回false。
获得锁的同时会给锁加入过期时间,防止客户端宕机导致锁无法释放,进而导致死锁。
redission分布式锁实现原理是什么?
在redis分布式锁的基础原理上,redission使用lua脚本操作redis保证操作的原子性(lua脚本保证操作原子性:当redis执行lua脚本的时候会暂停所有其他命令,直到lua脚本执行完成,但当lua脚本执行失败时,redis不会回滚,而是直接继续执行其他命令,不能保证一致性)
当客户端线程获取锁成功后,有一个看门狗程序判断当前任务在预期过期时间到达时是否执行完成,如不能完成则增加过期时间。
除此之外,获取不到锁的客户端线程会不断自旋,直到获取锁为止。
但是redis分布式锁无法保证主从一致性,即在redis集群部署时,通过redis分布式锁仍然是不安全的,因为redis分布式锁只会在一个节点上申请,如果该节点数据未同步时宕机,则其他节点没有该锁的信息,在申请锁的线程执行到一半时,其他线程又可以获得锁,就会出现“超卖”现象。