一、分布式锁——Redis
1、分布式锁在项目中的应用场景?
- 1、系统是一个分布式系统,集群,java锁已经锁不住了
- 2、操作共享资源,比如说库里的唯一的用户数据
- 3、同步访问,即多个进程同时操作共享资源
2、分布式锁有哪些解决方案?
-
1、Redis的分布式锁,很多大公司会基于做扩展开发 setnx key value,redisson
watch dog 防止key过期而我的程序没有执行万
-
2、基于zookeeper,顺序节点,临时节点
-
3、基于数据库,比如mysql,主键或唯一索引的唯一性
3、Redis做分布式锁用什么命令
SETNX
格式:setnx key value 将key的值设为value,当且仅当key不存在。
若给定的key已经存在,则setnx不做任何动作,操作失败
setnx 是SET if Not exists
(如果不存在,则set的简写)
加锁:set key value nx ex 10s
释放锁:delete key
4、Redis做分布式锁死锁有哪些情况,如何解决
情况1:加锁,没有释放锁。需要加释放锁的操作,比如 delete key
情况2:加锁后,程序没有执行释放锁,程序挂了。需要用的key的过期机制
5、Redis如何做分布式锁
假设有两个服务A,B都希望获得锁,执行过程如下:
第一步:服务A为了获取锁,向Redis发起了如下的命令:SET productid:lock value
NX EX 30000,其中,‘productid’由自己定义,一般与本次业务的id有关, value是一串随机值,必须保证全局的唯一性, NX指的是当且仅当key在Redis中不存在的时候执行成功,否则失败, EX 30000指的是在30秒后key自动删除,执行成功后返回成功,表明服务成功获得了锁
第二步:服务B为了得到多,向Redis发起同样的命令,但是由于Redis中存在同名的key,且并未过去,因此执行命令失败,服务B 未能获得锁,服务B进入循环请求的状态,比如每秒向Redis发起请求,直达成功获取到锁
第三步:服务A的业务代码执行时间超过30秒了,导致key过期,因此Redis自动删除了key。此时服务B再次发送命令执行成功,假设本次请求中设置的value为0000222,此时需要在服务A中对key进行续期,watch dog
第四步:服务A执行完毕,为了释放锁,服务A会主动向Redis发起删除key的命令,注意:删除key前,一定要判断服务A持有的value与redis内存存储的value是否一致。
一般使用的是lua脚本,具体如下:
if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1])\
else
return 0
end
二、分布式锁——ZooKeeper
1、基于ZooKeeper的分布式锁的实现原理 ?
顺序节点的特性:
使用ZooKeeper的顺序节点特性,假如我们在/lock/目录下创建三个节点,节点分别为/lock/00000001、/lock/00000002、/lock/00000003,最后一位数是一次递增的,节点名由zk来完成
临时节点的特性:
ZK中还有一个名为临时节点的节点,临时节点由某个客户端创建,当客户端与ZK集群断开连接,则该节点自动被删除,EPHEMERAL_AEQUENTIAL为临时顺序节点
根据ZK中节点是否存在,可以作为分布式锁的状态,以此来实现一个分布式锁,下面是分布式锁的逻辑:
1、客户端1调用create()方法创建名为/业务ID/lock的临时节点
2、客户端1调用getChildren(“业务ID”)方法来获取所有已经创建的子节点
3、客户端获取收到的所有的子节点path之后,如果发现自己在步骤1中创建的节点是所有序号最小的,就是看自己创建的序列号是否排第一,如果是第一,那么认为这个客户端1获得了锁,在他前面没有别的客户端拿到锁
4、如果创建的节点不是所有的节点中需要最小的,那么则监视比自己创建节点的序列号小的最大节点,进入等待,直到下次监视的节点变更的时候,再进行节点的获取,判断是否获取锁。
2、ZooKeeper和Redis做分布式锁有什么区别
Redis:
1.Redis只保持最终一致性,副本件的数据复制是异步进行的(set是写,get是读,Redis集群一般是读写分离的架构,存在主从同步延迟的情况),主从切换之后可能有部分数据没有复制过去可能会丢数据情况,故一般强一致性的业务不推荐使用Redis,而是使用ZK
2.Redis集群各方法的响应时间均为最低,随着并发量和业务数量的提升其影响时间会有明显的提升,但是极限qps可以达到最大且基本无异常
Redis集群的两种形式:
ZooKeeper:
1、使用ZooKeeper集群,锁原理是使用的ZooKeeper的顺序节点,临时节点的生命周期在client与集群的session结束时候结束。因此如果某个client节点存在网络问题,与ZooKeeper集群断开连接,session超时同样会导致锁被错误释放,ZooKeeper无法保证完全一致
2、ZooKeeper有较好的稳定性,响应时间抖动很小,没有出现异常,但是随着开发量和业务数量的提升其响应时间和qps会明显下降
总结:
1.ZK每次进行锁操作前都要创建若干节点,完成后要释放节点,会浪费时间
2.Redis只是简单的数据操作,没有这个问题