使用Zookeeper实现分布式锁
zk实现分布式锁的3种方式
第1种
创建一个znode,如果创建成功,则获取到锁,操作完成,删除znode即可释放锁;
如果创建失败(抛出异常),说明锁被其它服务的线程持有,当前线程休眠一小会儿,之后重试,设置一个计数器,如果重试指定次数后还没有获取到锁,就放弃。
缺点:未获取到锁时重试多次,浪费资源
第2种
在1的基础修改,如果创建失败,说明锁已被其它线程持有,给zndoe加一个watcher,监听节点删除事件(释放锁),当前线程休眠,节点删除事件发生时唤醒等待的线程。
缺点:会发生惊群现象,如果多个服务同时等待、监听此节点,释放锁后多个服务的线程都会被唤醒,但只有一个服务的线程可以获取到锁,其它服务的线程刚醒来又要沉睡。
第3种
在2的基础上进行修改,先创建有序的znode,假设都放在/lock下;
获取/lock的子节点列表,如果列表中只有一个元素,这个元素肯定是刚刚创建节点,认为当前线程已获取到锁;如果列表中的元素数量>1,获取倒数第二个元素,监听它的节点删除事件。
有序节点,获取子节点列表时,子节点是按照由小到大的顺序排列的,比如 [order0000000000, order0000000001, order0000000002,...] ,刚刚创建的节点是列表的最后一个元素,监听前一个节点即可。
用一个变量保存列表的最后一个元素(自己创建的有序节点),操作完成后删除这个节点。
无论使用哪一种,创建节点的时候,一定要创建临时节点,避免获取到锁后机器故障,导致锁一直释放不了。
可以自己动手使用原生API实现zk的分布式锁,麻烦些;也可以使用现有的轮子Curator。