以下内容为个人整理网上博客,侵删
Zookeeper
实现
锁即为临时节点,在获取锁的时候在locker节点下创建临时顺序节点,释放锁的时候删除该临时节点
-
客户端调用createNode()方法在locker下创建临时顺序节点,然后调用getChildren(“locker”)来获取locker下面的所有子节点
-
根据所有的子节点路径,判断自己创建的子节点序号是否最小,是最小的就认为该客户端获取到了锁
-
如果发现自己创建的节点并非所有子节点中最小的,说明还没有获取到锁。此时客户端需要找到比自己创建的节点小的那个节点,然后对其调用exist()方法,同时对其注册事件监听器
-
之后如果这个被关注的节点删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听
原理
-
临时节点的创建和释放是线程安全的
-
临时节点的创建是有先后顺序的
-
当前节点前面没有其他节点时获得锁
-
释放锁时删除当前节点并通知当前节点的监听者
特征
-
ZAB协议
-
Node存储模型
-
Watcher机制
Redis
实现
-
客户端调用setnx/set(key作为锁的名称,value作为业务唯一标志值一般使用当前时间戳,预期原有值为null,一定要设置过期时间)将key/value写入redis,成功即获得锁
-
客户端调用setnx/set时,如锁已存在,即预期原有值不为null,写入失败。此时通过value记录的加锁时间戳判断锁是否已超时,如已超时则重复以上步骤尝试获得锁
-
客户端调用del释放锁
原理
-
setnx/set(带有期望值)操作是具有原子性的
-
setnx/set将key写入成功时获得锁
-
key已存在时写入操作失败不能获得锁
-
del删除对应key时释放锁
如何解决死锁问题
已获得锁的客户端因为各种异常情况导致程序停止运营,锁无法依赖客户端进行释放,此时该锁也无法被其他客户端获得
Zookeeper:原生的实现逻辑就不存在此问题,由客户端创建的临时节点,当客户端与Zookeeper集群断开连接时,该节点自动被删除
Redis:通过key超时自动释放锁
参考文献