1.步骤
# 共享资源
127.0.0.1:6379> set num 10
OK
# 加锁
127.0.0.1:6379> setnx lock 1
(integer) 1
# 修改共享资源
127.0.0.1:6379> incrby num -1
(integer) 9
# 解锁
127.0.0.1:6379> del lock
(integer) 1
2. 原理
- setnx:只有要设置的key不存在时,我们才添加这个key-value。否则不添加
3. 补充
- 为了防止加锁后因为一些原因没有释放锁,可以选择给锁设置过期时间。
补充
1. 分布式锁应该具备哪些条件
- 在分布式系统环境下,一个方法在同一时间只能被一台机器的一个线程执行
- 高可用的获取锁和释放锁
- 高性能的获取锁和释放锁、
- 具备可重入性
- 具备锁失效机制,防止死锁
- 具备非阻塞特性,可以在没获取到锁的情况下立即返回获取锁失败
2. 分布式锁的三种实现方式
- 基于数据库
- 利用唯一索引,多线程获取锁,同时向数据库插入同一个key(唯一约束),谁插入成功则谁获取锁成功,之后处理完业务在删除该条记录
- 是否具备可重入:插入时添加附加消息可以实现可重入
- 没有锁失效机制
- 不具备阻塞锁特性
- 数据库比redis慢
- 基于redis
- redis有很高的性能
- redis的命令对分布式锁支持较好
- 有锁失效机制
- 基于zookeeper实现
3. zookeeper实现分布式锁
1. 一些概念
![](https://i-blog.csdnimg.cn/blog_migrate/1120fd9cde8f09abfbaaa7844f42e289.png)
- zookeeper的数据存储结构类似于 目录结构,像一棵树,树由节点组成,节点znode分为四种类型
1.1 持久节点
- 默认节点类型,创建节点的客户端与zookeeper断开连接后,该节点依旧存在
1.2 持久顺序节点
- 就是在创建节点时,zookeeper根据创建的时间顺序给该节点名称进行编号
1.3 临时节点
- 持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除
1.4 临时顺序节点
- 在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与Zookeeper断开连接后,临时节点会被删除。
2. zookeeper分布式锁原理
2.1 获取锁
- 客户端1 想要获取锁时,在某个节点下(ParentLock)下创建临时顺序节点Lock1,
- 之后客户端1就查找ParentLock节点下所有临时节点并按时间排序,然后判断自己锁创建的节点是不是顺序最靠前的,如果是第一个节点,则成功获取锁
- 如果此时再有客户端2来获取锁,也会在ParentLock节点下创建临时顺序节点Lock2
- 然后客户端2发现自己加的节点Lock2不是顺序最靠前的,于是客户端2向排序仅比它靠前一位节点Lock1注册Watcher
- 同理有客户端3也添加临时顺序节点Lock3,向Lock2注册watcher
2.2 释放锁
- 如果客户端1奔溃,关联的节点Lock1也会自动删除,当然也可以主从删除节点Lock1
- 此时客户端2会收到通知,然后客户端2尝试再次加锁,从而顺利获取到锁
3. redis与zookeeper做分布式锁的比较
3.1 redis
- set和del指令性能比较高
- 但实现复杂,要考虑超时,原子性,误删等情况,没有等待锁队列,只能在客户端处自旋等待,效率低下
3.2 zookeeper
- 有封装好的框架(redis也有),容易实现,有等待锁的队列,大大提升抢锁的效率
- 删除和添加节点性能较低
3. zookeeper保证ap还是cp
3.1 zookeeper写入流程
- 客户端向zookeeper发送一个写的请求,如果当前server不是leader,则会把请求转发给leader
- leader收到后开始发起Proposal到Follower,Follower收到来自Leader的提议后,会返回ack响应
- 当leader收到过半的ack响应后,就会发送commit提交数据,然后向客户单返回写入成功
- 若有新的Follower加入进来,也会对Leader进行数据同步,从而达到集群数据一致性
3.2 zookeeper读取过程
- 客户端向zookeeper发出读请求后,无论请求的是leader还是follower,都会直接返回结果。(这样你可能会读到脏数据)
- 如果使用sync读取,则会先与leader进行数据同步,这样会读取到最新的数据
3.3 总结
- 是保证ap还是保证cp,感觉看你怎么操作。
- 如果你读取过程中,能读到脏数据,那么就是ap
- 如果你读取过程中,采用sync再读取,保证每次读取最新数据,那么就是cp
- 其实是基于base理论
3.4 补充
- zookeeper在leader选举期间,会暂停对外提供服务。需要通过leader来保证数据的一致性
4. redis实现分布式锁原理
4.1 不可重入redis分布式锁
- 原理
- 利用setnx的互斥性
- 利用ex避免死锁
- 释放锁时判断线程标识
- 缺点
4.2 可重入的redis分布式锁
- 原理
- 利用hash结构,记录线程标识(字段)和重入次数(value)
- 利用watchDog延续锁时间
- 利用信号量(发布订阅)控制锁重试等待
- 缺点
- 集群环境下redis宕机引起锁失效问题(主节点宕机,从节点还未同步数据)
4.3 redisson的multiLock
- 原理
- 多个独立的redis节点,必须在所有节点都获取可重入锁之后,才算获取锁成功。
- 缺点