数据库分布式锁
Redis实现分布式锁
ZooKeeper实现分布式锁
=======》
1.「锁的互斥性」:在分布式集群应用中,共享资源的锁在同一时间只能被一个对象获取。
2. 「可重入」:为了避免死锁,这把锁是可以重入的,并且可以设置超时。
3. 「高效的加锁和解锁」:能够高效的加锁和解锁,获取锁和释放锁的性能也好。
4. 「阻塞、公平」:可以根据业务的需要,考虑是使用阻塞、还是非阻塞,公平还是非公平的锁。
数据库分布式锁:
在数据库的分布式锁的实现中,分为「悲观锁和乐观锁」,「悲观锁的实现依赖于数据库自身的锁机制实现」。
--》悲观锁
当一个数据库表被加上了排它锁,其它的客户端是不能够再对加锁的数据行加任何的锁,只能等待当前持有锁的释放锁。
排它锁是基于InnoDB存储引擎的,在执行操作的时候,在sql中加入for update
,可以给数据行加上排它锁。
在代码的层面上使用connection.commit();
,便可以释放锁,但是数据库复杂的加锁和解锁、事务等一系列消耗性能的操作,终归是无法抗高并发。
--》乐观锁
数据库乐观锁的方式实现分布式锁是基于「版本号控制」的方式实现,类似于「CAS的思想」,它认为操作的过程并不会存在并发的情况,只有在update version
的时候才会去比较。
Redis实现的分布式锁:
Redis实现分布式锁的 方式,可以使用setnx、getset、expire、del
这四个命令来实现。
setnx
:命令表示如果key不存在,就会执行set命令,若是key已经存在,不会执行任何操作。getset
:将key设置为给定的value值,并返回原来的旧value值,若是key不存在就会返回返回nil 。expire
:设置key生存时间,当当前时间超出了给定的时间,就会自动删除key。del
:删除key,它可以删除多个key,语法如下:DEL key [key …]
,若是key不存在直接忽略。
ZK实现的分布式锁:
ZK实现的分布式锁的原理是基于一个「临时顺序节点」实现的,开始的时候,首先会在ZK中创建一个ParentLock持久化节点。
当有client1请求锁的时候,,就会在ParentLock下创建一个临时顺序节点
当client1创建完临时顺序节点后,就会检查ParentLock下面的所有的子节点,会判断自己前面是否还有节点,此时明显是没有的,所以获取锁成功
当第二个客户端client2进来获取锁的时候,也会执行相同的逻辑,会先在创建一个临时的顺序节点,并且序号是排在第一个节点的后面
并且第二步也会判断ParnetLock下面的所有的子节点,看自己是否是第一个,明显不是,此时就会加锁失败。
那么此时client2会创建一个对client1的lock1的监听(Watcher
),用于监听lock1是否存在,同时client2会进入等待状态
当client1执行完自己的业务逻辑之后,就会删除锁,删除锁很简单,就是把这个lock1给删除掉
此时就会通知client2:监听的lock1已经被删除,锁被释放,此时client2创建的lock2也就变成了第一个节点,尝试获取所得时候就会获取锁成功。