回答什么是分布式锁
分布式锁相对他的应用场景,即有两个线程同时访问对数据库进行写的操作,这就需要考虑访问的时候我们如何操作.
分布式锁实现注意的问题
1-可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。
2-这把锁要是一把可重入锁(避免死锁)
这里解释一下什么是重入锁-可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。
场景-线程获得锁的时候宕机-出现了死锁
可重入锁参考-http://www.jianshu.com/p/007bd7029faf
3-这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
理想的情况则是; 在线程竞争不激烈的情况下,使用自旋锁也是可重入锁,竞争激烈的情况下使用,阻塞锁。
因为阻塞锁不会占用CPU资源
4-有高可用的获取锁和释放锁功能
5-获取锁和释放锁的性能要好
实现分布式锁-基于数据库
1-对表字段做唯一性约束-线程请求-获取唯一字段-相当于拿到了锁.
2-使用MySQL自带的排他锁-在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。
场景细节参考-http://www.weizijun.cn/2016/03/17/%E8%81%8A%E4%B8%80%E8%81%8A%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E7%9A%84%E8%AE%BE%E8%AE%A1/
实现分布式锁-基于Redis
线程 A 检查锁是否存在(get)–>否–>加锁(set),在 A 发起加锁命令但是还没有加锁成功的时候,可能线程 B 已经完成了set操作,锁被 B 获得,但是 A 也发起了加锁请求,由于set命令并不检查 key 的存在,B 的锁很可能会被 A 的set操作破坏。
幸运的是,redis 提供了另一个命令setx: 当指定的 key 不存在时,设置 key 的值为指定 value,如果存在,不做任何操作,成功则返回 1,失败则返回 0。也就是只要命令返回成功,线程就能正确获得锁,不需要再做类似get检查操作。
使用setx可以消除网络延迟对锁设置的影响。
锁释放的过程,首先检查客户端是否仍然持有该锁,如果持有,则在事务中删除键值对,释放锁的所有权。
参考详细-http://wecatch.me/blog/2016/08/20/distributed-lock-with-redis/
什么场景使用分布式锁-Reids
如果是为了效率(efficiency)而使用分布式锁,允许锁的偶尔失效,那么使用单Redis节点的锁方案就足够了,简单而且效率高。Redlock则是个过重的实现(heavyweight)。
如果是为了正确性(correctness)在很严肃的场合使用分布式锁,那么不要使用Redlock。它不是建立在异步模型上的一个足够强的算法,它对于系统模型的假设中包含很多危险的成分(对于timing)。而且,它没有一个机制能够提供fencing token。那应该使用什么技术呢?Martin认为,应该考虑类似Zookeeper的方案,或者支持事务的数据库。
参考-https://mp.weixin.qq.com/s/JTsJCDuasgIJ0j95K8Ay8w
实现分布式锁-基于ZooKeeper
ZooKeeper实现分布式锁利用了其临时子节点的如下特性:
在/exclusive_lock节点下创建临时子节点/exclusive_lock/lock,zk会保证在所有的客户端中,最终只有一个客户端能够创建成功,即可以认为该客户端获得了锁。同时,虽有没有获取到所得客户端需要到/exclusive_lock节点上注册一个子节点变更的Watcher监听,以便实时监听到lock节点的变更情况。
因为在获取锁时,创建的是一个临时节点/exclusive_lock/lock,因此在如下情况,都有可能释放锁:
获取锁的机器发生宕机,临时节点被zk移除
正常执行业务逻辑后,客户端主动删除临时节点
无论什么情况下,lock节点被移除,zk都会通知所有在/exclusive_lock节点上注册了子节点变更的Watcher监听的客户端。这些客户端在收到通知后,重新发起分布式锁的获取流程。
详细参考-http://www.jianshu.com/p/83881a79a0c8
-https://yiqiwuliao.com/post/java/zookeeper-shi-xian-fen-bu-shi-suo
文章严重参考,并且作者详细说明了各个解决方案遇到的问题和解决思路
https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650120465&idx=1&sn=26fefc34e461dac09b87eb577ae064e2&chksm=f36bbc30c41c3526f22ecd2182850e9b0fb146050cef3e7a2940cbb711ddd55384111541697a&mpshare=1&scene=1&srcid=1108yFRXkT2iol2JKikclVWQ#rd