(19)分布式锁的实现方案
1 说说分布式锁的实现方案?
相比单例锁,分布式锁需要解决的问题:
- 互斥性:任意时刻只能有一个客户端拥有锁,不能同时多个客户端获取。
- 安全性:锁只能被持有该锁的用户删除,而不能被其他用户删除。
- 死锁:获取锁的客户端因为某些原因而宕机,而未能释放锁,其他客户端无法获取此锁,需要有机制来避免该类问题的发生。
- 容错:当部分节点宕机,客户端仍能获取锁或者释放锁。
常用的方案是基于Redis集群的锁实现,常用的Java组件是Redission。它对Redis分布式锁的实现非常完善,实现可重入锁、读写锁、公平锁、信号量、CountDownLatch等很多种复杂的锁的语义,满足我们对分布式锁的不同层次的需求。
2 主从模式下节点宕机可能导致锁失效,Redission怎么解决的?
Client向Master获取锁之后同步给Slave,如果Client获取锁成功之后Master节点挂掉,并且未将该锁同步到Slave,之后在Sentinel的帮助下Slave升级为Master但是并没有之前未同步的锁的信息,此时如果有新的Client要在新Master获取锁,那么将可能出现两个Client持有同一把锁的问题。所以为了解决这个问题,可以设置一个唯一值random_value,用来校验自己的锁只能自己释放。Redission实现了Redlock算法解决这个问题。
3 说说Redlock算法的原理?
假设有5个Redis master实例:
- 客户端获取服务器当前的的时间t0,毫秒数。
- 使用相同的key和value依次向5个实例获取锁。客户端在获取锁的时候自身设置一个远小于业务锁需要的持续时间的超时时间。举个例子,假设锁需要10秒,超时时间可以设置成比如5-50毫秒。这个避免某个Redis本身已经挂了,但是客户端一直在尝试获取锁的情况。超时了之后就直接跳到下一个节点。
- 客户端通过当前时间(t1)减去t0,计算获取锁所消耗的时间t2(t1-t0)。只有t2小于锁的业务有效时间(也就是第二步的10秒),并且,客户端在至少3(5/2+1)台上获取到锁我们才认为锁获取成功。
- 如果锁已经获取,那么锁的业务有效时间为10s-t2。
- 如果客户端没有获取到锁,可能是没有在大于等于N/2+1个实例上获取锁,也可能是有效时间(10s-t2)为负数,我们就尝试去释放锁,即使是并没有在那个节点上获取到。
4 Redlock算法有什么缺点吗?
时间偏差在分布式系统中很常见,在锁有效时间里虽然减去了时钟偏移,但是这个值不太好确定。Redis作者也建议对锁互斥的安全性要求高的应用不要使用这个算法。
5 单节点Redis锁怎么实现?
在单Redis节点中,分布式锁通常使用 SET lock_key NX PX 5000
。NX 代表只在键不存在时,才对键进行设置操作;PX 5000 设置键的过期时间为5000毫秒。
参考
https://www.jianshu.com/p/47fd7f86c848
https://www.jianshu.com/p/2d3bf2ff2315
https://www.cnblogs.com/sheldon-lou/p/11039795.html
https://www.cnblogs.com/luocaodan/p/10949558.html