Zookeeper分布式锁的实现和原理

Zookeeper的使用典型场景之一:分布式锁

使用zk的分布式锁,无非是通过zk的两大特性:节点和事件监听

互斥锁:

1)创建临时顺序节点

2)判断是否是临时顺序节点最小的,如果是,直接获得锁,如果不是,对之前的一个节点进行监听

3)获得锁,处理业务逻辑,释放锁,即delete节点,监听当前节点的后续节点收到事件通知,开始从第二步循环

采用这种方式,每个线程对应的只需要监听一个节点,避免了多个线程竞争一个节点,可以缓解服务端压力,效率较高。这种实现是公平锁、互斥锁。

读写锁:

使用互斥锁,如果同一时间大量的请求涌入是会性能下降的,但是实际上很多情况下不是所有的请求都需要阻塞的,通过zk同样可以实现读写锁。

写入的时候,后来的请求不能读,同样也不能写。读的时候,后面的请求可以读,但是不能写。基于这样的原理,需要监听的节点就少了很多。读读之间不需要监听,如果有写,需要监听。

写锁实际上可以看作是互斥锁。

 

zk分布式锁的具体代码实现,可以使用Apache开源的一款zk客户端Curator,实现起来相当简单。

使用springboot项目,引入依赖:

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.0.0</version>
</dependency>

注入客户端:

@Bean(initMethod = "start")
public CuratorFramework curatorFramework() {
  RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
  CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.0.15:2181", retryPolicy);
  return client;
}
# 互斥锁demo
InterProcessMutex interProcessMutex = new InterProcessMutex(curatorFramework, "/item_" + id); try { // 一直等待,直到加锁成功 interProcessMutex.acquire(); // TODO: 2020-11-24 业务逻辑 } catch (Exception e) {   if (e instanceof RuntimeException) {     throw e; } } finally { interProcessMutex.release(); }
# 读写锁实现demo,可以加读锁或者写锁
InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(curatorFramework, "/item_" + id); // InterProcessMutex interProcessMutex = interProcessReadWriteLock.readLock(); InterProcessMutex interProcessMutex = interProcessReadWriteLock.writeLock(); try {   interProcessMutex.acquire();   // TODO: 2020-11-24 业务逻辑 } catch (Exception e) {   if (e instanceof RuntimeException) {     throw e;   } } finally {   interProcessMutex.release(); }

curator客户端已经帮我们封装好了,我们只需要专注处理业务逻辑即可。

具体的原理也可以进到curator源码中去看,就是基于上面的原则去实现的。

 

posted @ 2020-11-24 21:35  以战止殇  阅读(609)  评论(0编辑  收藏  举报