分布式锁通俗解读( 三 )


那就等于是服务器2和服务器3都拿到锁了 , 那就问题大了 。这个时候怎么办呢?
这个时候需要用到“GETSET key value”命令了 。这个命令的意思就是获取当前key的值 , 并且设置新的值 。
假设服务器2发现key过期了 , 开始调用getset命令 , 然后用获取的时间判断是否过期 , 如果获取的时间仍然是过期的 , 那就说明拿到锁了 。
如果没有 , 则说明在服务2执行getset之前 , 服务器3可能也发现锁过期了 , 并且在服务器2之前执行了getset操作 , 重新设置了过期时间 。
那么服务器2就需要放弃后续的操作 , 继续等待服务器3释放锁或者去监测key的有效期是否过期 。
这块其实有一个小问题是 , 服务器3已经修改了有效期 , 拿到锁之后 , 服务器2也修改了有效期 , 但是没能拿到锁 , 但是这个有效期的时间已经被在服务器3的基础上有增加一些 , 但是这种影响其实还是很小的 , 几乎可以忽略不计 。
2、为什么Zookeeper可实现分布式锁?
ZooKeeper是一个分布式的 , 开放源码的分布式应用程序协调服务 , 是google的Chubby一个开源的实现 , 是Hadoop和Hbase的重要组件 。那对于我们初次认识的人 , 可以理解成ZooKeeper就像是我们的电脑文件系统 , 我们可以在d盘中创建文件夹a , 并且可以继续在文件夹a中创建文件夹a1 , a2 。
那我们的文件系统有什么特点?那就是同一个目录下文件名称不能重复 , 同样ZooKeeper也是这样的 。
在ZooKeeper所有的节点 , 也就是文件夹称作Znode , 而且这个Znode节点是可以存储数据的 。我们可以通过“ create /zkjjj nice”来创建一个节点 , 这个命令就表示 , 在跟目录下创建一个zkjjj的节点 , 值是nice 。同样这里的值 , 和我在前面说的Redis中的一样 , 没什么意义 , 你随便给 。
另外ZooKeeper可以创建4种类型的节点 , 分别是:

  • 持久性节点
  • 持久性顺序节点
  • 临时性节点
  • 临时性顺序节点
首先说下持久性节点和临时性节点的区别:
  • 持久性节点表示只要你创建了这个节点 , 那不管你ZooKeeper的客户端是否断开连接 , ZooKeeper的服务端都会记录这个节点;
  • 临时性节点刚好相反 , 一旦你ZooKeeper客户端断开了连接 , 那ZooKeeper服务端就不再保存这个节点;
  • 顺便也说下顺序性节点 , 顺序性节点是指 , 在创建节点的时候 , ZooKeeper会自动给节点编号比如0000001 , 0000002这种的 。
Zookeeper有一个监听机制 , 客户端注册监听它关心的目录节点 , 当目录节点发生变化(数据改变、被删除、子目录节点增加删除)等 , Zookeeper会通知客户端 。
四、在Zookeeper中如何加锁?
下面我们继续结合我们上面的分红包场景 , 描述下在Zookeeper中如何加锁 。
假设服务器1 , 创建了一个节点 /zkjjj , 成功了 , 那服务器1就获取了锁 , 服务器2再去创建相同的锁 , 就会失败 , 这个时候就只能监听这个节点的变化 。
等到服务器1处理完业务 , 删除了节点后 , 他就会得到通知 , 然后去创建同样的节点 , 获取锁处理业务 , 再删除节点 , 后续的100台服务器与之类似 。
注意这里的100台服务器并不是挨个去执行上面的创建节点的操作 , 而是并发的 , 当服务器1创建成功 , 那么剩下的99个就都会注册监听这个节点 , 等通知 , 以此类推 。
但是大家有没有注意到 , 这里还是有问题的 , 还是会有死锁的情况存在 , 对不对?
当服务器1创建了节点后挂了 , 没能删除 , 那其他99台服务器就会一直等通知 , 那就完蛋了 。。。
这个时候就需要用到临时性节点了 , 我们前面说过了 , 临时性节点的特点是客户端一旦断开 , 就会丢失 , 也就是当服务器1创建了节点后 , 如果挂了 , 那这个节点会自动被删除 , 这样后续的其他服务器 , 就可以继续去创建节点 , 获取锁了 。


推荐阅读