简化的结构图如下:
文章插图
三、分布式锁的实现有哪些?
说到分布式锁的实现 , 还是有很多的 , 有数据库方式的 , 有redis分布式锁 , 有Zookeeper分布式锁等等 。
我们如果采用Redis作为分布式锁 , 那么上图中负“责红包的妹子(服务)” , 就可以替换成Redis , 请自行脑补 。
1、为什么Redis可以实现分布式锁?
首先Redis是单线程的 , 这里的单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性) , 即一个线程处理所有网络请求 , 其他模块仍用了多个线程 。
在实际的操作中过程大致是这样子的:
服务器1要去访问发红包的妹子 , 也就是Redis , 那么他会在Redis中通过"setnx key value" 操作设置一个key进去 , value是啥不重要 , 重要的是要有一个key , 也就是一个标记 , 而且这个key你爱叫啥叫啥 , 只要所有的服务器设置的key相同就可以 。
假设我们设置一个 , 如下图:
文章插图
那么我们可以看到会返回一个1 , 那就代表了成功 。
如果再来一个请求去设置同样的key , 如下图:
文章插图
这个时候会返回0 , 那就代表失败了 。
那么我们就可以通过这个操作去判断是不是当前可以拿到锁 , 或者说可以去访问“负责发红包的妹子” , 如果返回1 , 那我就开始去执行后面的逻辑 , 如果返回0 , 那就说明已经被人占用了 , 我就要继续等待 。
当服务器1拿到锁之后 , 进行了业务处理 , 完成后 , 还需要释放锁 , 如下图所示:
文章插图
删除成功返回1 , 那么其他的服务器就可以继续重复上面的步骤去设置这个key , 以达到获取锁的目的 。
当然以上的操作是在Redis客户端直接进行的 , 通过程序调用的话 , 肯定就不能这么写 , 比如java就需要通过jedis去调用 , 但是整个处理逻辑基本都是一样的 。
通过上面的方式 , 我们好像是解决了分布式锁的问题 , 但是想想还有没有什么问题呢?
对 , 问题还是有的 , 可能会有死锁的问题发生 , 比如服务器1设置完之后 , 获取了锁之后 , 忽然发生了宕机 。那后续的删除key操作就没法执行 , 这个key会一直在Redis中存在 , 其他服务器每次去检查 , 都会返回0 , 他们都会认为有人在使用锁 , 我需要等 。
为了解决这个死锁的问题 , 我们就需要给key设置有效期了 。
设置的方式有2种:
- 第一种就是在set完key之后 , 直接设置key的有效期 "expire key timeout" , 为key设置一个超时时间 , 单位为second , 超过这个时间锁会自动释放 , 避免死锁 。
- 第二种方式 , 就是把删除key权利交给其他的服务器 , 那这个时候就需要用到value值了 , 比如服务器1 , 设置了value也就是timeout为当前时间+1秒 , 这个时候服务器2通过get发现时间已经超过系统当前时间了 , 那就说明服务器1没有释放锁 , 服务器1可能出问题了 , 服务器2就开始执行删除key操作 , 并且继续执行setnx操作 。
推荐阅读
- iOS设备修改锁屏底部字样详解
- 手机密码忘了怎么办?要怎么开锁呢?
- 分布式系统:时间、时钟和事件序列
- Redis实现分布式锁与Zookeeper实现分布式锁区别
- 揭秘华为分布式技术
- iphone相册加密码锁,保护隐私
- 基于redis来实现的分布式锁
- 分布式数据中心的五大优势
- Redis:解决分布式高并发修改同一个Key的问题
- 正确的红茶保存方法锁住健康真滋味